1 package kawa.lang;
2 import gnu.mapping.*;
3 import gnu.expr.*;
4 import gnu.kawa.reflect.*;
5 import gnu.bytecode.ArrayClassLoader;
6 import gnu.bytecode.ClassType;
7 import gnu.bytecode.Field;
8 import gnu.bytecode.Member;
9 import gnu.bytecode.Type;
10 import gnu.bytecode.ZipLoader;
11 import gnu.text.SourceMessages;
12 import gnu.lists.*;
13 import gnu.kawa.lispexpr.*;
14 import java.util.*;
15 import gnu.kawa.functions.GetNamedPart;
16 import gnu.kawa.functions.CompileNamedPart;
17 import gnu.kawa.functions.MakeSplice;
18 import gnu.kawa.functions.MultiplyOp;
19 import gnu.kawa.functions.Expt;
20 import gnu.kawa.xml.XmlNamespace;
21 import gnu.math.DFloNum;
22 import gnu.math.IntNum;
23 import gnu.math.Unit;
24 import gnu.text.Char;
25 import gnu.text.SourceLocator;
26 import gnu.text.StandardNamedChars;
27 /* #ifdef enable:XML */
28 import gnu.xml.NamespaceBinding;
29 /* #endif */
30 import kawa.standard.Scheme;
31 import kawa.standard.require.DeclSetMapper;
32 
33 /** Used to translate from source to Expression.
34  * The result has macros expanded, lexical names bound, etc, and is
35  * ready for code generation.
36  * This is sometimes called a "compilation environment",
37  * but we modify it as we go along - there is a single Translator for
38  * each top-level form.
39  */
40 
41 public class Translator extends Compilation
42 {
43   // Global environment used to look for syntax/macros.
44   private Environment env;
45 
46   /** Set if we're processing (as opposed to expanding)
47    * a <code>define-syntax</code> or <code>defmacro</code>. */
48   public Macro currentMacroDefinition;
49 
50   /** Innermost current scope of pattern variable,
51    * from a <code>syntax-case</code>. */
52   public PatternScope patternScope;
53 
54   public Declaration templateScopeDecl;
55 
56   /** A "mark" created for the current macro application.
57    * This is (more-or-less) the mark specified by the syntax-case
58    * specification (in r6rs-lib), applied to the output of a transformer.
59    * However, instead of "applying" a mark to the transformer output,
60    * we remember in the TemplateScope an object unique to the application.
61    */
62   Object currentMacroMark = null;
63 
64   /** A variable to hold the matched values for syntax-case
65    * pattern variables. */
66   public Declaration matchArray;
67 
68   /** A stack of aliases pushed by <code>pushRenamedAlias</code>. */
69   private Stack<Declaration> renamedAliasStack;
70 
71   public Object pendingForm;
72 
73   public LambdaExp curMethodLambda;
74 
75   /* #ifdef enable:XML */
76   public NamespaceBinding xmlElementNamespaces = NamespaceBinding.predefinedXML;
77   /* #endif */
78 
79   public static final Declaration getNamedPartDecl;
80   static {
81     // Declare the special symbol $lookup$ (from the reader)
82     // and bind it to getNamedPartDecl.
83     String cname = "gnu.kawa.functions.GetNamedPart";
84     String fname = "getNamedPart";
85     getNamedPartDecl = Declaration.getDeclarationFromStatic(cname, fname);
86     LispLanguage.getNamedPartLocation.setDeclaration(getNamedPartDecl);
87   }
88 
89   private static Expression errorExp = new ErrorExp ("unknown syntax error");
90 
Translator(Language language, SourceMessages messages, NameLookup lexical, Environment env)91     public Translator(Language language, SourceMessages messages,
92                       NameLookup lexical, Environment env) {
93         super(language, messages, lexical);
94         this.env = env;
95     }
96 
Translator(Language language, SourceMessages messages, NameLookup lexical)97     public Translator(Language language, SourceMessages messages,
98                       NameLookup lexical) {
99         super(language, messages, lexical);
100         this.env = Environment.getCurrent();
101     }
102 
103     @Override
getGlobalEnvironment()104     public final Environment getGlobalEnvironment() { return env; }
105 
parse(Object input)106   public Expression parse (Object input)
107   {
108     return rewrite(input);
109   }
110 
rewrite_car(Pair pair, SyntaxForm syntax)111   public final Expression rewrite_car (Pair pair, SyntaxForm syntax)
112   {
113     return rewrite_car(pair, syntax == null ? current_scope : syntax.getScope());
114   }
115 
rewrite_car(Pair pair, ScopeExp templateScope)116   public final Expression rewrite_car (Pair pair, ScopeExp templateScope)
117   {
118     if (templateScope == current_scope
119 	|| pair.getCar() instanceof SyntaxForm)
120       return rewrite_car(pair, false);
121     ScopeExp save_scope = setPushCurrentScope(templateScope);
122     try
123       {
124 	return rewrite_car(pair, false);
125       }
126     finally
127       {
128 	setPopCurrentScope(save_scope);
129       }
130   }
131 
rewrite_car(Pair pair, boolean function)132   public final Expression rewrite_car (Pair pair, boolean function)
133   {
134     Object car = pair.getCar();
135     if (pair instanceof PairWithPosition)
136       return rewrite_with_position (car, function, (PairWithPosition) pair);
137     else
138       return rewrite (car, function);
139   }
140 
141     /** Similar to rewrite_car.
142      * However, we check for (quasiquote exp) specially, and handle that
143      * directly.  This is in case quasiquote isn't in scope.
144      */
rewrite_car_for_lookup(Pair pair)145     public final Expression rewrite_car_for_lookup(Pair pair) {
146         Object car = pair.getCar();
147         if (car instanceof Pair) {
148             Pair pcar = (Pair) car;
149             if (pcar.getCar() == LispLanguage.quasiquote_sym) {
150                 Object pos = pushPositionOf(pair);
151                 Expression ret = Quote.quasiQuote.rewrite(pcar.getCdr(), this);
152                 popPositionOf(pos);
153                 return ret;
154             }
155         }
156         return rewrite_car(pair, false);
157     }
158 
159   Syntax currentSyntax;
getCurrentSyntax()160   public Syntax getCurrentSyntax() { return currentSyntax; }
161 
162   /**  The module instance containing the current macro.
163    * This is only used temporarily, set when resolving a Declaration
164    * bound to a macro, and used to set the macroContext field of the
165    * TemplateScope created when expanding the macro's template(s). */
166   Declaration macroContext;
167 
168   /**
169    * Apply a Syntax object.
170    * @param syntax the Syntax object whose rewrite method we call
171    * @param form the syntax form (including the macro name)
172    * @return the re-written form as an Expression object
173    */
apply_rewrite(Syntax syntax, Pair form)174   Expression apply_rewrite (Syntax syntax, Pair form)
175   {
176     Expression exp = errorExp;
177     Syntax saveSyntax = currentSyntax;
178     currentSyntax = syntax;
179     try
180       {
181 	exp = syntax.rewriteForm(form, this);
182       }
183     finally
184       {
185         currentSyntax = saveSyntax;
186       }
187     return exp;
188   }
189 
190   /** Check if declaraton is an alias for some other name.
191    * This is needed to chase identifiers renamed for hygienic macro
192    * expansion - see SyntaxRules.expand. */
getOriginalRef(Declaration decl)193   static ReferenceExp getOriginalRef(Declaration decl)
194   {
195     if (decl != null && decl.isAlias() && ! decl.isIndirectBinding())
196       {
197 	Expression value = decl.getValue();
198 	if (value instanceof ReferenceExp)
199 	  return (ReferenceExp) value;
200       }
201     return null;
202   }
203 
keywordsAreSelfEvaluating()204     public final boolean keywordsAreSelfEvaluating() {
205         return ((LispLanguage) getLanguage()).keywordsAreSelfEvaluating();
206     }
207 
selfEvaluatingSymbol(Object obj)208   public final boolean selfEvaluatingSymbol (Object obj)
209   {
210     return ((LispLanguage) getLanguage()).selfEvaluatingSymbol(obj);
211   }
212 
213   /** True iff a form matches a literal symbol. */
matches(Object form, String literal)214   public final boolean matches(Object form, String literal)
215   {
216     return matches(form, null, literal);
217   }
218 
matches(Object form, SyntaxForm syntax, String literal)219   public boolean matches(Object form, SyntaxForm syntax, String literal)
220   {
221     if (syntax != null)
222       {
223         // FIXME
224       }
225     if (form instanceof SyntaxForm)
226       {
227 	// FIXME
228 	form = ((SyntaxForm) form).getDatum();
229       }
230     if (form instanceof SimpleSymbol && ! selfEvaluatingSymbol(form))
231       {
232 	ReferenceExp rexp = getOriginalRef(lexical.lookup(form, -1));
233 	if (rexp != null)
234 	  form = rexp.getSymbol();
235       }
236     return form instanceof SimpleSymbol
237       && ((Symbol) form).getLocalPart() == literal;
238   }
239 
matches(Object form, SyntaxForm syntax, Symbol literal)240   public boolean matches(Object form, SyntaxForm syntax, Symbol literal)
241   {
242     if (syntax != null)
243       {
244         // FIXME
245       }
246     if (form instanceof SyntaxForm)
247       {
248 	// FIXME
249 	form = ((SyntaxForm) form).getDatum();
250       }
251     if (form instanceof SimpleSymbol && ! selfEvaluatingSymbol(form))
252       {
253 	ReferenceExp rexp = getOriginalRef(lexical.lookup(form, -1));
254 	if (rexp != null)
255 	  form = rexp.getSymbol();
256       }
257     return form == literal;
258   }
259 
matchQuoted(Pair pair)260   public Object matchQuoted (Pair pair)
261   {
262     if (matches(pair.getCar(), LispLanguage.quote_str)
263         && pair.getCdr() instanceof Pair
264         && (pair = (Pair) pair.getCdr()).getCdr() == LList.Empty)
265       return pair.getCar();
266     return null;
267   }
268 
lookup(Object name, int namespace)269   public Declaration lookup(Object name, int namespace)
270   {
271     Declaration decl = lexical.lookup(name, namespace);
272     if (decl != null && getLanguage().hasNamespace(decl, namespace))
273       return decl;
274     return currentModule().lookup(name, getLanguage(), namespace);
275   }
276 
277   /** Find global Declaration, creating one if not found. */
lookupGlobal(Object name)278   public Declaration lookupGlobal(Object name)
279   {
280     return lookupGlobal(name, -1);
281   }
282 
283   /** Find global Declaration, creating one if not found. */
lookupGlobal(Object name, int namespace)284   public Declaration lookupGlobal(Object name, int namespace)
285   {
286     ModuleExp module = currentModule();
287     Declaration decl = module.lookup(name, getLanguage(), namespace);
288     if (decl == null)
289       {
290         decl = module.getNoDefine(name);
291         decl.setIndirectBinding(true);
292       }
293     return decl;
294   }
295 
296   /** Check if a Declaration is bound to a Syntax.
297    * @param decl the Declaration to check
298    * @return the Syntax bound to decl, or null.
299    * In the former case, macroContext may be set as a side effect.
300    */
check_if_Syntax(Declaration decl)301   Syntax check_if_Syntax (Declaration decl)
302   {
303     Declaration d = Declaration.followAliases(decl);
304     Object obj = null;
305     Expression dval = d.getValue();
306     if (dval != null && d.getFlag(Declaration.IS_SYNTAX))
307       {
308         try
309           {
310             if (decl.getValue() instanceof ReferenceExp)
311               {
312                 Declaration context
313                   = ((ReferenceExp) decl.getValue()).contextDecl();
314                 if (context != null)
315                   macroContext = context;
316                 else if (current_scope instanceof TemplateScope)
317                   macroContext = ((TemplateScope) current_scope).macroContext;
318               }
319             else if (current_scope instanceof TemplateScope)
320               macroContext = ((TemplateScope) current_scope).macroContext;
321             obj = dval.eval(env);
322           }
323         catch (Error ex)
324           {
325             ex.printStackTrace();
326             throw ex;
327           }
328         catch (Throwable ex)
329           {
330             ex.printStackTrace();
331             error('e', "unable to evaluate macro for "+decl.getSymbol());
332           }
333       }
334     else if (decl.getFlag(Declaration.IS_SYNTAX) && ! decl.needsContext())
335       {
336 	StaticFieldLocation loc = StaticFieldLocation.make(decl);
337 	obj = loc.get(null);
338       }
339 
340     return obj instanceof Syntax ? (Syntax) obj : null;
341   }
342 
rewrite_pair(Pair p, boolean function)343   public Expression rewrite_pair (Pair p, boolean function)
344   {
345     Object p_car = p.getCar();
346     Expression func;
347     boolean useHelper = true;
348     if (p_car instanceof Pair
349         && ((Pair) p_car).getCar() == LispLanguage.splice_sym) {
350         func = gnu.kawa.reflect.MakeAnnotation.makeAnnotationMaker
351             (rewrite_car((Pair) ((Pair) p_car).getCdr(), false));
352         useHelper = false;
353     }
354     else
355         func = rewrite_car (p, true);
356     Object proc = null;
357     if (func instanceof QuoteExp)
358       {
359         proc = func.valueIfConstant();
360         if (proc instanceof Syntax)
361           return apply_rewrite((Syntax) proc, p);
362       }
363     ReferenceExp ref = null;
364     if (func instanceof ReferenceExp)
365       {
366 	ref = (ReferenceExp) func;
367         Declaration decl = ref.getBinding();
368 	if (decl == null)
369 	  {
370 	    Object sym = ref.getSymbol();
371 	    Symbol symbol;
372 	    String name;
373 	    if (sym instanceof Symbol && ! selfEvaluatingSymbol(sym))
374 	      {
375 		symbol = (Symbol) sym;
376 		name = symbol.getName();
377 	      }
378 	    else
379 	      {
380 		name = sym.toString();
381 		symbol = env.getSymbol(name);
382 	      }
383 	    proc = env.get(symbol,
384 			   getLanguage().hasSeparateFunctionNamespace()
385 			   ? EnvironmentKey.FUNCTION
386 			   : null,
387 			   null);
388 	    if (proc instanceof Syntax)
389 	      return apply_rewrite ((Syntax) proc, p);
390             if (proc instanceof AutoloadProcedure)
391               {
392                 try
393                   {
394                     proc = ((AutoloadProcedure) proc).getLoaded();
395                   }
396                 catch (RuntimeException ex)
397                   {
398                     proc = null;
399                   }
400               }
401 	  }
402         else
403 	  {
404             Declaration saveContext = macroContext;
405             Syntax syntax = check_if_Syntax (decl);
406             if (syntax != null)
407               {
408                 Expression e = apply_rewrite (syntax, p);
409                 macroContext = saveContext;
410                 return e;
411               }
412 	  }
413 
414 	ref.setProcedureName(true);
415 	if (getLanguage().hasSeparateFunctionNamespace())
416 	  func.setFlag(ReferenceExp.PREFER_BINDING2);
417       }
418 
419     boolean isNamedPartDecl = func instanceof ReferenceExp
420         && (((ReferenceExp) func).getBinding()==getNamedPartDecl);
421     if (isNamedPartDecl)
422       useHelper = false;
423 
424     Object cdr = p.getCdr();
425     int cdr_length = listLength(cdr);
426 
427     if (cdr_length < 0)
428       return syntaxError
429           ("improper list (circular or dotted) is not allowed here");
430     Expression applyFunction =  useHelper ? applyFunction(func) : null;
431 
432     Stack vec = new Stack();
433     if (applyFunction != null) {
434         vec.add(func);
435         func = applyFunction;
436     }
437 
438     ScopeExp save_scope = current_scope;
439     int first_keyword = -1;
440     int last_keyword = -1;
441     boolean bad_keyword_reported = false;
442     int firstSpliceArg = -1;
443     int i = 0;
444     while (cdr != LList.Empty)
445       {
446 	if (cdr instanceof SyntaxForm)
447 	  {
448 	    SyntaxForm sf = (SyntaxForm) cdr;
449 	    cdr = sf.getDatum();
450 	    // I.e. first time do equivalent of setPushCurrentScope
451             if (current_scope == save_scope)
452               lexical.pushSaveTopLevelRedefs();
453 	    setCurrentScope(sf.getScope());
454 	  }
455         Object save_pos = pushPositionOf(cdr);
456 	Pair cdr_pair = (Pair) cdr;
457         Object cdr_car = cdr_pair.getCar();
458         Object cdr_cdr = cdr_pair.getCdr();
459         Expression arg;
460         if (cdr_car instanceof Keyword) {
461             if (first_keyword < 0) {
462                 first_keyword = i;
463                 last_keyword = i - 2; // To suppress incorrect warnings
464             }
465             if (bad_keyword_reported)
466                 ;
467             else if (keywordsAreSelfEvaluating())
468                 last_keyword = i;
469             else if (i == last_keyword + 1 || i + 1 == cdr_length) {
470                 bad_keyword_reported = true;
471                 error('w', "missing value after unquoted keyword");
472             } else if (i != last_keyword + 2) {
473                 bad_keyword_reported = true;
474                 error('w', "keyword separated from other keyword arguments");
475             } else
476                 last_keyword = i;
477             arg = QuoteExp.getInstance(cdr_car, this);
478             arg.setFlag(QuoteExp.IS_KEYWORD);
479         } else if (cdr_cdr instanceof Pair
480                    // FIXME should check binding for ... is builtin ...
481                    && ((Pair) cdr_cdr).getCar() == LispLanguage.dots3_sym) {
482             LambdaExp dotsLambda = new LambdaExp();
483             pushScanContext(dotsLambda);
484             dotsLambda.body = rewrite_car(cdr_pair, false);
485             ScanContext scanContext = getScanContext();
486             LinkedHashMap<Declaration,Declaration> sdecls
487                 = scanContext.decls;
488             int nseqs = sdecls.size();
489             ArrayList<Expression> scanExps = scanContext.scanExpressions;
490             int nexps = scanExps == null ? 0 : scanExps.size();
491             Expression[] subargs = new Expression[nseqs + nexps + 1];
492             subargs[0] = dotsLambda;
493             popScanContext();
494             Iterator<Declaration> sit = sdecls.keySet().iterator();
495             int j = 1;
496             while (sit.hasNext()) {
497                 Declaration sdecl = sit.next();
498                 if (curScanNesting() > 0) {
499                     sdecl = getScanContext().addSeqDecl(sdecl);
500                 }
501                 ReferenceExp rexp = new ReferenceExp(sdecl);
502                 subargs[j++] = rexp;
503             }
504             for (int k = 0; k < nexps; k++) {
505                 subargs[j++] = scanExps.get(k);
506             }
507             arg = new ApplyExp(Scheme.map, subargs);
508             arg = new ApplyExp(MakeSplice.quoteInstance, arg);
509             cdr_cdr = ((Pair) cdr_cdr).getCdr();
510             if (firstSpliceArg < 0)
511                 firstSpliceArg = i + (applyFunction != null ? 1 : 0);
512         } else {
513             Object cdr_car_car;
514             if (cdr_car instanceof Pair
515                 && ((cdr_car_car = ((Pair) cdr_car).getCar()) == LispLanguage.splice_sym
516                     || cdr_car_car == LispLanguage.splice_colon_sym)) {
517                 arg = rewrite_car((Pair) ((Pair) cdr_car).getCdr(), false);
518                 QuoteExp splicer = cdr_car_car == LispLanguage.splice_sym
519                     ? MakeSplice.quoteInstance
520                     : MakeSplice.quoteKeywordsAllowedInstance;
521                 arg = new ApplyExp(splicer, arg);
522                 if (firstSpliceArg < 0)
523                     firstSpliceArg = i + (applyFunction != null ? 1 : 0);
524             }
525             else
526                 arg = rewrite_car (cdr_pair, false);
527         }
528         i++;
529 
530         vec.addElement(arg);
531 	cdr = cdr_cdr;
532         popPositionOf(save_pos);
533       }
534 
535 
536     Expression[] args = new Expression[vec.size()];
537     vec.copyInto(args);
538 
539     if (save_scope != current_scope)
540       setPopCurrentScope(save_scope);
541 
542     if (isNamedPartDecl)
543         return rewrite_lookup(args[0], args[1], function);
544 
545     ApplyExp app = new ApplyExp(func, args);
546     app.firstSpliceArg = firstSpliceArg;
547     if (first_keyword >= 0)
548       {
549         app.numKeywordArgs = (last_keyword - first_keyword) / 2 + 1;
550         app.firstKeywordArgIndex = first_keyword + (applyFunction != null ? 2 : 1);
551       }
552     return app;
553   }
554 
rewrite_lookup(Expression part1, Expression part2, boolean function)555     public Expression rewrite_lookup(Expression part1, Expression part2, boolean function) {
556         Symbol sym = namespaceResolve(part1, part2);
557         if (sym != null)
558           return rewrite(sym, function);
559         // FIXME don't copy the args array in makeExp ...
560         return CompileNamedPart.makeExp(part1, part2);
561     }
562 
namespaceResolvePrefix(Expression context)563   public Namespace namespaceResolvePrefix (Expression context)
564   {
565     if (context instanceof ReferenceExp)
566       {
567         ReferenceExp rexp = (ReferenceExp) context;
568         Declaration decl = rexp.getBinding();
569         Object val;
570         if (decl == null || decl.getFlag(Declaration.IS_UNKNOWN))
571           {
572             Object rsym = rexp.getSymbol();
573             Symbol sym = rsym instanceof Symbol ? (Symbol) rsym
574               : env.getSymbol(rsym.toString());
575             val = env.get(sym, null);
576           }
577         else if (decl.isNamespaceDecl())
578           {
579             val = decl.getConstantValue();
580           }
581         else
582           val = null;
583         if (val instanceof Namespace)
584           {
585             Namespace ns = (Namespace) val;
586             String uri = ns.getName();
587             if (uri != null && uri.startsWith("class:"))
588               return null;
589             return ns;
590           }
591       }
592     return null;
593   }
594 
namespaceResolve(Namespace ns, Expression member)595   public Symbol namespaceResolve (Namespace ns, Expression member)
596   {
597     if (ns != null && member instanceof QuoteExp)
598       {
599         String mem = ((QuoteExp) member).getValue().toString().intern();
600         return ns.getSymbol(mem);
601       }
602     return null;
603   }
604 
namespaceResolve(Expression context, Expression member)605   public Symbol namespaceResolve (Expression context, Expression member)
606   {
607     return namespaceResolve(namespaceResolvePrefix(context), member);
608   }
609 
stripSyntax(Object obj)610   public static Object stripSyntax (Object obj)
611   {
612     while (obj instanceof SyntaxForm)
613       obj = ((SyntaxForm) obj).getDatum();
614     return obj;
615   }
616 
safeCar(Object obj)617   public static Object safeCar (Object obj)
618   {
619     while (obj instanceof SyntaxForm)
620       obj = ((SyntaxForm) obj).getDatum();
621     if (! (obj instanceof Pair))
622       return null;
623     return stripSyntax(((Pair) obj).getCar());
624   }
625 
safeCdr(Object obj)626   public static Object safeCdr (Object obj)
627   {
628     while (obj instanceof SyntaxForm)
629       obj = ((SyntaxForm) obj).getDatum();
630     if (! (obj instanceof Pair))
631       return null;
632     return stripSyntax(((Pair) obj).getCdr());
633   }
634 
635   /** Returns the length of a syntax list.
636    * Returns Integer.MIN_VALUE for cyclic lists.
637    * For impure lists returns the negative of one more than
638    * the number of pairs before the "dot".
639    * Similar to LList.listLength, but handles SyntaxForm more efficiently. */
listLength(Object obj)640   public static int listLength(Object obj)
641   {
642     // Based on list-length implementation in
643     // Guy L Steele jr: "Common Lisp:  The Language", 2nd edition, page 414
644     int n = 0;
645     Object slow = obj;
646     Object fast = obj;
647     for (;;)
648       {
649 	// 'n' is number of previous Pairs before 'fast' cursor.
650 	while (fast instanceof SyntaxForm)
651 	  fast = ((SyntaxForm) fast).getDatum();
652 	while (slow instanceof SyntaxForm)
653 	  slow = ((SyntaxForm) slow).getDatum();
654 	if (fast == LList.Empty)
655 	  return n;
656 	if (! (fast instanceof Pair))
657 	  return -1-n;
658 	n++;
659 	Object next = ((Pair) fast).getCdr();
660 	while (next instanceof SyntaxForm)
661 	  next = ((SyntaxForm) next).getDatum();
662 	if (next == LList.Empty)
663 	  return n;
664 	if (! (next instanceof Pair))
665 	  return -1-n;
666 	slow = ((Pair)slow).getCdr();
667 	fast = ((Pair)next).getCdr();
668 	n++;
669 	if (fast == slow)
670 	  return Integer.MIN_VALUE;
671       }
672   }
673 
rewriteInBody(Object exp)674   public void rewriteInBody (Object exp)
675   {
676     if (exp instanceof SyntaxForm)
677       {
678 	SyntaxForm sf = (SyntaxForm) exp;
679 	ScopeExp save_scope = setPushCurrentScope(sf.getScope());
680 	try
681 	  {
682 	    rewriteInBody(sf.getDatum());
683 	  }
684 	finally
685 	  {
686 	    setPopCurrentScope(save_scope);
687 	  }
688       }
689     else if (exp instanceof ValuesFromLList)
690       {
691           // Optimization of following case.
692           // More importantly, we make use of the line number information.
693           for (Object vs = ((ValuesFromLList) exp).values;
694                vs != LList.Empty; )
695           {
696               Pair p = (Pair) vs;
697               pushForm(rewrite_car(p, false));
698               vs = p.getCdr();
699           }
700       }
701     else if (exp instanceof Values)
702       {
703 	Object[] vals = ((Values) exp).getValues();
704 	for (int i = 0;  i < vals.length;  i++)
705 	  rewriteInBody(vals[i]);
706       }
707     else {
708         Expression e = rewrite(exp, false);
709         setLineOf(e);
710         pushForm(e);
711     }
712   }
713 
getCompletions(Environment env, String nameStart, Object property, String namespaceUri, List<? super String> matches)714     public int getCompletions(Environment env,
715                               String nameStart, Object property,
716                               String namespaceUri,
717                               List<? super String> matches) {
718         LocationEnumeration e = env.enumerateAllLocations();
719         int count = 0;
720         while (e.hasMoreElements()) {
721             Location loc = e.nextLocation();
722             Symbol sym = loc.getKeySymbol();
723             String local = sym == null ? null : sym.getLocalPart();
724             if (local != null && local.startsWith(nameStart)
725                 && property == loc.getKeyProperty()
726                 && namespaceUri == sym.getNamespaceURI()) {
727                 count++;
728                 matches.add(local);
729             }
730         }
731         return count;
732     }
733 
namespaceResolve(Object name)734     public Object namespaceResolve(Object name) {
735         Object prefix = null;
736         Expression part2 = null;
737         Pair p;
738         if (name instanceof Pair
739             && safeCar(p = (Pair) name) == LispLanguage.lookup_sym
740             && p.getCdr() instanceof Pair
741             && (p = (Pair) p.getCdr()).getCdr() instanceof Pair) {
742             prefix = namespaceResolve(p.getCar());
743             if (! (stripSyntax(prefix) instanceof Symbol))
744                 return name;
745             part2 = rewrite_car_for_lookup((Pair) p.getCdr());
746         }
747         else if (name instanceof Symbol) {
748             Symbol s = (Symbol) name;
749             if (s.hasUnknownNamespace()) {
750                 String loc = s.getLocalPart();
751                 prefix = Symbol.valueOf(s.getPrefix());
752                 part2 = QuoteExp.getInstance(Symbol.valueOf(s.getLocalPart()));
753             }
754         }
755         if (part2 != null) {
756             Expression part1 = rewrite(prefix);
757             Symbol sym = namespaceResolve(part1, part2);
758             if (sym != null)
759                 return sym;
760             String combinedName = CompileNamedPart.combineName(part1, part2);
761             if (combinedName != null)
762                 return Namespace.EmptyNamespace.getSymbol(combinedName);
763         }
764         return name;
765     }
766 
767     /**
768      * Re-write a Scheme expression in S-expression format into internal form.
769      */
rewrite(Object exp)770     public Expression rewrite(Object exp) {
771         return rewrite(exp, 'N');
772     }
773 
774     /**
775      * Re-write a Scheme expression in S-expression format into internal form.
776      */
rewrite(Object exp, boolean function)777     public Expression rewrite(Object exp, boolean function) {
778         return rewrite(exp, function ? 'F' : 'N');
779     }
780 
781     /** Re-write a Scheme expression in S-expression format into internal form.
782      * @param mode either 'N' (normal), 'F' (function application context),
783      *  'M' (macro-checking) or 'Q' (colon-form in quote).
784      */
rewrite(Object exp, char mode)785     public Expression rewrite(Object exp, char mode) {
786         if (exp instanceof SyntaxForm) {
787             SyntaxForm sf = (SyntaxForm) exp;
788             ScopeExp save_scope = setPushCurrentScope(sf.getScope());
789             try {
790                 Expression s = rewrite(sf.getDatum(), mode);
791                 return s;
792             } finally {
793                 setPopCurrentScope(save_scope);
794             }
795         }
796         boolean function = mode != 'N';
797         if (exp instanceof Pair && mode != 'Q') {
798             Expression e = rewrite_pair((Pair) exp, function);
799             setLineOf(e);
800             return e;
801         } else if (exp instanceof Symbol && ! selfEvaluatingSymbol(exp)) {
802             Symbol s = (Symbol) exp;
803 
804             // Check if we're handling a completion request.
805             int complete = s.getLocalName()
806                 .indexOf(CommandCompleter.COMPLETE_REQUEST);
807             boolean separate = getLanguage().hasSeparateFunctionNamespace();
808             if (complete >= 0) {
809                 List<String> candidates = new ArrayList<String>();
810                 String prefix = s.toString().substring(0, complete);
811                 Object property = function && separate ? EnvironmentKey.FUNCTION
812                     : null;
813                 int symspace = function ? Language.FUNCTION_NAMESPACE
814                     : Language.VALUE_NAMESPACE;
815                 getCompletions(env, prefix, property, s.getNamespaceURI(),
816                                candidates);
817                 lexical.getCompletingSymbols(prefix, symspace,
818                                              candidates);
819                 throw new CommandCompleter(complete, candidates,
820                                            prefix, prefix.length(), this);
821             }
822 
823             if (s.hasUnknownNamespace()) {
824                 String loc = s.getLocalPart();
825                 return rewrite_lookup(rewrite(Symbol.valueOf(s.getPrefix()), false),
826                                       QuoteExp.getInstance(Symbol.valueOf(s.getLocalPart())),
827                                       function);
828             }
829             Declaration decl = lexical.lookup(exp, function);
830             Declaration cdecl = null;
831 
832             // If we're nested inside a class (in a ClassExp) then the field
833             // and methods names of this class and super-classes/interfaces
834             // need to be searched.
835             ScopeExp scope = current_scope;
836             int decl_nesting = decl == null ? -1 : ScopeExp.nesting(decl.context);
837             String dname;
838             if (exp instanceof SimpleSymbol)
839                 dname = exp.toString();
840             else {
841                 dname = null;
842                 scope = null;
843             }
844             for (;scope != null; scope = scope.getOuter()) {
845                 if (scope instanceof LambdaExp
846                     && scope.getOuter() instanceof ClassExp // redundant? FIXME
847                     && ((LambdaExp) scope).isClassMethod()
848                     && mode != 'M') {
849                     if (decl_nesting >= ScopeExp.nesting(scope.getOuter()))
850                         break;
851                     LambdaExp caller = (LambdaExp) scope;
852                     ClassExp cexp = (ClassExp) scope.getOuter();
853                     ClassType ctype = (ClassType) cexp.getClassType();
854                     // If ctype is a class that hasn't been compiled yet (and
855                     // ClassExp#declareParts hasn't been called yet)
856                     // then we may may get a tentative Field created
857                     // by ClassExp#createFields.
858                     // BUG: This doesn't work for not-yet compiled methods.
859                     Member part = SlotGet.lookupMember(ctype, dname, ctype);
860                     boolean contextStatic
861                         = (caller == cexp.clinitMethod
862                            || (caller != cexp.initMethod
863                                && caller.nameDecl.isStatic()));
864                     if (part == null) {
865                         PrimProcedure[] methods
866                             = ClassMethods.getMethods(ctype, dname,
867                                                       contextStatic ? 'S' : 'V',
868                                                       ctype, language);
869                         if (methods.length == 0)
870                             continue;
871                     } else {
872                         gnu.expr.SourceName snameAnn =
873                             part.getAnnotation(gnu.expr.SourceName.class);
874                         String pname = snameAnn == null ? part.getName()
875                             : snameAnn.name();
876                         if (! dname.equals(pname))
877                             continue;
878                     }
879                     Expression part1;
880                     // FIXME We're throwing away 'part', which is wasteful.
881                     if (contextStatic)
882                         part1 = new ReferenceExp(((ClassExp) caller.getOuter()).nameDecl);
883                     else
884                         part1 = new ThisExp(caller.firstDecl());
885                     return CompileNamedPart.makeExp(part1,
886                                                     QuoteExp.getInstance(dname));
887                 }
888             }
889 
890             Object nameToLookup;
891             if (decl != null) {
892                 nameToLookup = decl.getSymbol();
893                 exp = null;
894                 ReferenceExp rexp = getOriginalRef(decl);
895                 if (rexp != null) {
896                     decl = rexp.getBinding();
897                     if (decl == null) {
898                         exp = rexp.getSymbol();
899                         nameToLookup = exp;
900                     }
901                 }
902             } else {
903                 nameToLookup = exp;
904             }
905             Symbol symbol = (Symbol) exp;
906             if (decl != null) {
907                 if (current_scope instanceof TemplateScope && decl.needsContext())
908                     cdecl = ((TemplateScope) current_scope).macroContext;
909                 else if (decl.getFlag(Declaration.FIELD_OR_METHOD)
910                          && ! decl.isStatic()) {
911                     scope = currentScope();
912                     for (;;) {
913                         if (scope == null)
914                             throw new Error("internal error: missing "+decl);
915                         if (scope.getOuter() == decl.context) // I.e. same class.
916                             break;
917                         scope = scope.getOuter();
918                     }
919                     cdecl = scope.firstDecl();
920                 }
921             } else {
922                 Location loc
923                     = env.lookup(symbol,
924                                  function && separate ? EnvironmentKey.FUNCTION
925                                  : null);
926                 if (loc != null)
927                     loc = loc.getBase();
928                 if (loc instanceof FieldLocation) {
929                     FieldLocation floc = (FieldLocation) loc;
930                     try {
931                         decl = floc.getDeclaration();
932                         if (! inlineOk(null)
933                             // A kludge - we get a bunch of testsuite failures
934                             // if we don't inline $lookup$.  FIXME.
935                             && (decl != getNamedPartDecl
936                                 // Another kludge to support "object" as a
937                                 // type specifier.
938                                 && ! isObjectSyntax(floc.getDeclaringClass(),
939                                                     floc.getMemberName())))
940                             decl = null;
941                         else if (immediate) {
942                             if (! decl.isStatic()) {
943                                 cdecl = new Declaration("(module-instance)");
944                                 cdecl.setValue(new QuoteExp(floc.getInstance()));
945                             }
946                         } else if (decl.isStatic()) {
947                             // If the class has been loaded through ZipLoader
948                             // or ArrayClassLoader then it might not be visible
949                             // if loaded through some other ClassLoader.
950                             Class fclass = floc.getRClass();
951                             ClassLoader floader;
952                             if (fclass == null
953                                 || ((floader = fclass.getClassLoader())
954                                     instanceof ZipLoader)
955                                 || floader instanceof ArrayClassLoader)
956                                 decl = null;
957                         } else
958                             decl = null;
959                     } catch (Exception ex) {
960                         error('e',
961                               "exception loading '" + exp
962                               + "' - " + ex.getMessage());
963                         decl = null;
964                     }
965                 }
966                 else if (mode != 'M' && (loc == null || ! loc.isBound()))
967                 {
968                     Expression e = checkDefaultBinding(symbol, this);
969                     if (e != null)
970                         return e;
971                 }
972                 /*
973                 else if (Compilation.inlineOk && function) {
974                     // Questionable.  fail with new set_b implementation,
975                     // which just call rewrite_car on the lhs,
976                     // if we don't require function to be true.  FIXME.
977                     decl = Declaration.getDeclaration(proc);
978                 }
979                 */
980             }
981             if (decl != null) {
982                 // A special kludge to deal with the overloading between the
983                 // object macro and object as being equivalent to java.lang.Object.
984                 // A cleaner solution would be to use an identifier macro.
985                 Field dfield = decl.getField();
986                 if (! function && dfield != null
987                     && isObjectSyntax(dfield.getDeclaringClass(),
988                                       dfield.getName()))
989                     return QuoteExp.getInstance(Object.class);
990 
991                 if (decl.getContext() instanceof PatternScope)
992                     return syntaxError("reference to pattern variable "+decl.getName()+" outside syntax template");
993             }
994 
995             if (decl == null && function
996                 && nameToLookup==LispLanguage.lookup_sym) {
997                 decl = getNamedPartDecl;
998             }
999             int scanNesting = decl == null ? 0
1000                 : Declaration.followAliases(decl).getScanNesting();
1001             if (scanNesting > 0) {
1002                 if (scanNesting > curScanNesting())
1003                     error('e', "using repeat variable '"+decl.getName()+"' while not in repeat context");
1004                 else {
1005                     return new ReferenceExp
1006                         (scanContextStack.get(scanNesting-1).addSeqDecl(decl));
1007                 }
1008             }
1009             ReferenceExp rexp = new ReferenceExp (nameToLookup, decl);
1010             rexp.setContextDecl(cdecl);
1011             rexp.setLine(this);
1012             if (function && separate)
1013                 rexp.setFlag(ReferenceExp.PREFER_BINDING2);
1014             return rexp;
1015         } else if (exp instanceof LangExp)
1016             return rewrite(((LangExp) exp).getLangValue(), function);
1017         else if (exp instanceof Expression)
1018             return (Expression) exp;
1019         else if (exp == Special.abstractSpecial)
1020             return QuoteExp.abstractExp;
1021         else if (exp == Boolean.TRUE)
1022             return QuoteExp.trueExp;
1023         else if (exp == Boolean.FALSE)
1024             return QuoteExp.falseExp;
1025         else if (exp == Special.nativeSpecial)
1026             return QuoteExp.nativeExp;
1027         else {
1028             if (exp instanceof Keyword && ! keywordsAreSelfEvaluating())
1029                 error('w', "keyword should be quoted if not in argument position");
1030             if (exp instanceof String)
1031                 exp = new IString((String) exp);
1032             return QuoteExp.getInstance(Quote.quote(exp, this), this);
1033         }
1034     }
1035 
1036     /**
1037      * If a symbol is lexically unbound, look for a default binding.
1038      * The default implementation does the following:
1039      *
1040      * If the symbol is the name of an existing Java class, return that class.
1041      * Handles both with and without (semi-deprecated) angle-brackets:
1042      *   {@code <java.lang.Integer>} and {@code java.lang.Integer}.
1043      * Also handles arrays, such as {@code java.lang.String[]}.
1044      *
1045      * If the symbol starts with {@code '@'} parse as an annotation class.
1046      *
1047      * Recognizes quanties with units, such as {@code 2m} and {@code 3m/s^2}.
1048      *
1049      * Handles the xml and unit namespaces.
1050      *
1051      * @return null if no binding, otherwise an Expression.
1052      *
1053      * FIXME: This method should be refactored. The quantities parsing should
1054      *        be moved to its own method at least.
1055      */
checkDefaultBinding(Symbol symbol, Translator tr)1056     public Expression checkDefaultBinding(Symbol symbol, Translator tr) {
1057         Namespace namespace = symbol.getNamespace();
1058         String local = symbol.getLocalPart();
1059         String name = symbol.toString();
1060         int len = name.length();
1061 
1062         if (namespace instanceof XmlNamespace)
1063             return makeQuoteExp(((XmlNamespace) namespace).get(local));
1064         String namespaceName = namespace.getName();
1065         if (namespaceName == LispLanguage.unitNamespace.getName()) {
1066             Object val = Unit.lookup(local);
1067             if (val != null)
1068                 return makeQuoteExp(val);
1069         }
1070         if (namespaceName == LispLanguage.entityNamespace.getName()) {
1071             Object val = lookupStandardEntity(local);
1072             if (val == null) {
1073                 tr.error('e', "unknown entity name "+local);
1074                 val = "{"+namespace.getPrefix()+":"+local+"}";
1075             }
1076             return makeQuoteExp(val);
1077         }
1078 
1079         char ch0 = name.charAt(0);
1080 
1081         if (ch0 == '@') { // Deprecated - reader now returns ($splice$ ATYPE).
1082             String rest = name.substring(1);
1083             Expression classRef = tr.rewrite(Symbol.valueOf(rest));
1084             return MakeAnnotation.makeAnnotationMaker(classRef);
1085         }
1086 
1087         // Look for quantities.
1088         if (ch0 == '-' || ch0 == '+' || Character.digit(ch0, 10) >= 0) {
1089             // 1: initial + or -1 seen.
1090             // 2: digits seen
1091             // 3: '.' seen
1092             // 4: fraction seen
1093             // 5: [eE][=+]?[0-9]+ seen
1094             int state = 0;
1095             int i = 0;
1096 
1097             for (; i < len; i++) {
1098                 char ch = name.charAt(i);
1099                 if (Character.digit(ch, 10) >= 0)
1100                     state = state < 3 ? 2 : state < 5 ? 4 : 5;
1101                 else if ((ch == '+' || ch == '-') && state == 0)
1102                     state = 1;
1103                 else if (ch == '.' && state < 3)
1104                     state = 3;
1105                 else if ((ch == 'e' || ch == 'E') && (state == 2 || state == 4)
1106                          && i + 1 < len) {
1107                     int j = i + 1;
1108                     char next = name.charAt(j);
1109                     if ((next == '-' || next == '+') && ++j < len)
1110                         next = name.charAt(j);
1111                     if (Character.digit(next, 10) < 0)
1112                         break;
1113                     state = 5;
1114                     i = j + 1;
1115                 }
1116                 else
1117                     break;
1118             }
1119             tryQuantity:
1120             if (i < len && state > 1) {
1121                 DFloNum num = new DFloNum(name.substring(0, i));
1122                 boolean div = false;
1123                 ArrayList vec = new ArrayList();
1124                 for (; i < len;) {
1125                     char ch = name.charAt(i++);
1126                     if (ch == '*') {
1127                         if (i == len)
1128                             break tryQuantity;
1129                         ch = name.charAt(i++);
1130                     } else if (ch == '/') {
1131                         if (i == len || div)
1132                             break tryQuantity;
1133                         div = true;
1134                         ch = name.charAt(i++);
1135                     }
1136                     int unitStart = i - 1;
1137                     int unitEnd;
1138                     for (;;) {
1139                         if (!Character.isLetter(ch)) {
1140                             unitEnd = i - 1;
1141                             if (unitEnd == unitStart)
1142                                 break tryQuantity;
1143                             break;
1144                         }
1145                         if (i == len) {
1146                             unitEnd = i;
1147                             ch = '1';
1148                             break;
1149                         }
1150                         ch = name.charAt(i++);
1151                     }
1152                     vec.add(name.substring(unitStart, unitEnd));
1153                     boolean expRequired = false;
1154                     if (ch == '^') {
1155                         expRequired = true;
1156                         if (i == len)
1157                             break tryQuantity;
1158                         ch = name.charAt(i++);
1159                     }
1160                     boolean neg = div;
1161                     if (ch == '+') {
1162                         expRequired = true;
1163                         if (i == len)
1164                             break tryQuantity;
1165                         ch = name.charAt(i++);
1166                     } else if (ch == '-') {
1167                         expRequired = true;
1168                         if (i == len)
1169                             break tryQuantity;
1170                         ch = name.charAt(i++);
1171                         neg = !neg;
1172                     }
1173                     int nexp = 0;
1174                     int exp = 0;
1175                     for (;;) {
1176                         int dig = Character.digit(ch, 10);
1177                         if (dig <= 0) {
1178                             i--;
1179                             break;
1180                         }
1181                         exp = 10 * exp + dig;
1182                         nexp++;
1183                         if (i == len)
1184                             break;
1185                         ch = name.charAt(i++);
1186                     }
1187                     if (nexp == 0) {
1188                         exp = 1;
1189                         if (expRequired)
1190                             break tryQuantity;
1191                     }
1192                     if (neg)
1193                         exp = -exp;
1194                     vec.add(IntNum.make(exp));
1195                 }
1196                 if (i == len) {
1197                     int nunits = vec.size() >> 1;
1198                     Expression[] units = new Expression[nunits];
1199                     for (i = 0; i < nunits; i++) {
1200                         String uname = (String) vec.get(2 * i);
1201                         Symbol usym = LispLanguage.unitNamespace.getSymbol(uname.intern());
1202                         Expression uref = tr.rewrite(usym);
1203                         IntNum uexp = (IntNum) vec.get(2 * i + 1);
1204                         if (uexp.longValue() != 1)
1205                             uref = new ApplyExp(Expt.expt,
1206                                                 new Expression[] {
1207                                     uref, makeQuoteExp(uexp)
1208                                 });
1209                         units[i] = uref;
1210                     }
1211                     Expression unit;
1212                     if (nunits == 1)
1213                         unit = units[0];
1214                     else
1215                         unit = new ApplyExp(MultiplyOp.TIMES, units);
1216                     return new ApplyExp(MultiplyOp.TIMES,
1217                                         new Expression[] {
1218                             makeQuoteExp(num),
1219                             unit
1220                         });
1221                 }
1222             }
1223         }
1224 
1225         boolean sawAngle;
1226         if (len > 2 && ch0 == '<' && name.charAt(len - 1) == '>') {
1227             name = name.substring(1, len - 1);
1228             len -= 2;
1229             sawAngle = true;
1230         } else
1231             sawAngle = false;
1232         int rank = 0;
1233         while (len > 2 && name.charAt(len - 2) == '['
1234                && name.charAt(len - 1) == ']') {
1235             len -= 2;
1236             rank++;
1237         }
1238         //(future) String cname = (namespace == LispPackage.ClassNamespace) ? local : name;
1239         String cname = name;
1240         if (rank != 0)
1241             cname = name.substring(0, len);
1242         try {
1243             Type type = getLanguage().getNamedType(cname);
1244             if (rank > 0 && (!sawAngle || type == null)) {
1245                 Symbol tsymbol = namespace.getSymbol(cname.intern());
1246                 Expression texp = tr.rewrite(tsymbol, false);
1247                 texp = InlineCalls.inlineCalls(texp, tr);
1248                 if (!(texp instanceof ErrorExp))
1249                     type = tr.getLanguage().getTypeFor(texp);
1250             }
1251             if (type != null) {
1252                 // Somewhat inconsistent: Types named by getNamedType are Type,
1253                 // while standard type/classes are Class.  FIXME.
1254                 while (--rank >= 0) {
1255                     type = gnu.bytecode.ArrayType.make(type);
1256                 }
1257                 return makeQuoteExp(type);
1258             }
1259             Class clas;
1260             type = Type.lookupType(cname);
1261             if (type instanceof gnu.bytecode.PrimType)
1262                 clas = type.getReflectClass();
1263             else {
1264                 if (cname.indexOf('.') < 0)
1265                     cname = (tr.classPrefix
1266                              + Mangling.mangleNameIfNeeded(cname));
1267                 if (rank == 0) {
1268                     ModuleManager mmanager = ModuleManager.getInstance();
1269                     ModuleInfo typeInfo = mmanager.searchWithClassName(cname);
1270                     if (typeInfo != null) {
1271                         Compilation tcomp = typeInfo.getCompilation();
1272                         if (tcomp != null && tcomp.mainClass != null) {
1273                             QuoteExp qexp = new QuoteExp(tcomp.mainClass,
1274                                                          Type.javalangClassType);
1275                             qexp.setLocation(this);
1276                             return qexp;
1277                         }
1278                     }
1279                 }
1280 
1281                 clas = ClassType.getContextClass(cname);
1282             }
1283             if (clas != null) {
1284                 if (rank > 0) {
1285                     type = Type.make(clas);
1286                     while (--rank >= 0) {
1287                         type = gnu.bytecode.ArrayType.make(type);
1288                     }
1289                     clas = type.getReflectClass();
1290                 }
1291                 return makeQuoteExp(clas);
1292             }
1293         } catch (ClassNotFoundException ex) {
1294             Package pack = gnu.bytecode.ArrayClassLoader.getContextPackage(name);
1295             if (pack != null)
1296                 return makeQuoteExp(pack);
1297         } catch (NoClassDefFoundError ex) {
1298             tr.error('w', "error loading class " + cname + " - " + ex.getMessage() + " not found");
1299         } catch (Exception ex) {
1300         }
1301         if (name.startsWith("array")) {
1302             Type atype = LispLanguage.decodeArrayType(name);
1303             if (atype != null)
1304                 return makeQuoteExp(atype);
1305         }
1306 
1307         return null;
1308     }
1309 
1310     static Map<String,String> standardEntities;
1311     public static synchronized String lookupStandardEntity(String key) {
1312         if (standardEntities == null) {
1313             standardEntities = new HashMap<String,String>();
1314             Char.addNamedChars(standardEntities);
1315         }
1316         String val = standardEntities.get(key);
1317         if (val != null)
1318             return val;
1319         return val = StandardNamedChars.instance.get(key);
1320     }
1321 
1322   public static void setLine(Expression exp, Object location)
1323   {
1324     if (location instanceof SourceLocator)
1325       exp.setLocation((SourceLocator) location);
1326   }
1327 
1328   public static void setLine(Declaration decl, Object location)
1329   {
1330     if (location instanceof SourceLocator)
1331       decl.setLocation((SourceLocator) location);
1332   }
1333 
1334   PairWithPosition positionPair;
1335 
1336   /*
1337   public Object pushPositionOfCar(Object pair)
1338   {
1339     if (pair instanceof Pair)
1340       {
1341         Object car = ((Pair) pair).getCar();
1342         if (car instanceof PairWithPosition)
1343           pair = car;
1344       }
1345     return pushPositionOf(pair);
1346     }*/
1347 
1348   /** Note current line number position from a PairWithPosition.
1349    * Return an object to pass to popPositionOf.
1350    */
1351   public Object pushPositionOf(Object pos)
1352   {
1353     if (pos instanceof SyntaxForm)
1354       pos = ((SyntaxForm) pos).getDatum();
1355     PairWithPosition pair;
1356     if (pos instanceof PairWithPosition)
1357         pair = (PairWithPosition) pos;
1358     else if (pos instanceof SourceLocator)
1359         pair = new PairWithPosition((SourceLocator) pos, null, null);
1360     else
1361       return null;
1362     Object saved;
1363     if (positionPair == null
1364 	|| positionPair.getFileName() != getFileName()
1365 	|| positionPair.getLineNumber() != getLineNumber()
1366 	|| positionPair.getColumnNumber() != getColumnNumber())
1367       {
1368         saved = new PairWithPosition(this, this, positionPair);
1369       }
1370     else
1371       saved = positionPair;
1372     setLine(pos);
1373     positionPair = pair;
1374     return saved;
1375   }
1376 
1377   /** Restore  line number position from a previous pushPositionOf.
1378    * @param saved value returned by matching pushPositionOf.
1379    */
1380   public void popPositionOf(Object saved)
1381   {
1382     if (saved == null)
1383       return;
1384     setLine(saved);
1385     positionPair = (PairWithPosition) saved;
1386     if (positionPair.getCar() == this)
1387       positionPair = (PairWithPosition) positionPair.getCdr();
1388   }
1389 
1390     public void errorWithPosition(String message, Object form) {
1391         Object save = pushPositionOf(form);
1392         error('e', message);
1393         popPositionOf(save);
1394     }
1395 
1396     public void errorIfNonEmpty(Object form) {
1397         if (form != LList.Empty)
1398             error('e', "invalid improper (dotted) list");
1399     }
1400 
1401   /** Set the line position of the argument to the current position. */
1402 
1403   public void setLineOf (Expression exp)
1404   {
1405     // "Special" QuoteExps may be shared, but the position gets set (in the
1406     // call to QuoteExp.getInstance at end of re-write) for normal ones.
1407     if (exp instanceof QuoteExp)
1408       return;
1409     if (exp.getLineNumber() <= 0)
1410         exp.setLocation(this);
1411   }
1412 
1413   /** Extract a type from the car of a pair. */
1414   public Type exp2Type(Pair typeSpecPair)
1415   {
1416     return exp2Type(typeSpecPair, null, null);
1417   }
1418 
1419   public Type exp2Type(Pair typeSpecPair, Declaration decl, SyntaxForm syntax)
1420   {
1421     Object saved = pushPositionOf(typeSpecPair);
1422     try
1423       {
1424 	Expression texp = rewrite_car(typeSpecPair, syntax);
1425 	if (texp instanceof ErrorExp)
1426 	  return null;
1427         Type type = getLanguage().getTypeFor(texp);
1428         if (type == null)
1429           {
1430             try
1431               {
1432                 Object t = texp.eval(env);
1433                 if (t instanceof Class)
1434                   type = Type.make((Class) t);
1435                 else if (t instanceof Type)
1436                   type = (Type) t;
1437               }
1438             catch (Error ex)
1439               {
1440                 throw ex;
1441               }
1442             catch (Throwable ex)
1443               {
1444               }
1445           }
1446         if (type == null)
1447 	   {
1448 	     if (texp instanceof ReferenceExp)
1449 	       error('e', "unknown type name '"
1450 		     + ((ReferenceExp) texp).getName() + '\'');
1451 	     else
1452                error('e', "invalid type spec");
1453              type = Type.errorType;
1454 	   }
1455         if (decl != null)
1456           decl.setType(texp, type);
1457         return type;
1458       }
1459     finally
1460       {
1461 	popPositionOf(saved);
1462       }
1463   }
1464 
1465   public Expression rewrite_with_position (Object exp, boolean function,
1466                                            PairWithPosition pair)
1467   {
1468     Object saved = pushPositionOf(pair);
1469     Expression result;
1470     try
1471       {
1472 	if (exp == pair)
1473 	  result = rewrite_pair(pair, function);  // To avoid a cycle
1474 	else
1475 	  result = rewrite (exp, function);
1476 	setLineOf(result);
1477       }
1478     finally
1479       {
1480 	popPositionOf(saved);
1481       }
1482     return result;
1483   }
1484 
1485   public static Object wrapSyntax (Object form, SyntaxForm syntax)
1486   {
1487     if (syntax == null || form instanceof Expression)
1488       return form;
1489     else
1490       return SyntaxForms.fromDatumIfNeeded(form, syntax);
1491   }
1492 
1493   /** Pop from formStack all forms that come after beforeFirst.
1494    */
1495   public Values popForms(Pair beforeFirst)
1496   {
1497     Object tail = formStack.popTail(beforeFirst);
1498     if (tail == LList.Empty)
1499       return Values.empty;
1500     return new ValuesFromLList((LList) tail);
1501   }
1502 
1503   public void scanForm (Object st, ScopeExp defs)
1504   {
1505     if (st instanceof SyntaxForm)
1506       {
1507 	SyntaxForm sf = (SyntaxForm) st;
1508 	ScopeExp save_scope = setPushCurrentScope(sf.getScope());
1509 	try
1510 	  {
1511 	    Pair beforeFirst = formStack.last;
1512 	    scanForm(sf.getDatum(), defs);
1513 	    pushForm(wrapSyntax(popForms(beforeFirst), sf));
1514 	    return;
1515 	  }
1516 	finally
1517 	  {
1518 	    setPopCurrentScope(save_scope);
1519 	  }
1520       }
1521     if (st instanceof Values)
1522       {
1523 	if (st == Values.empty)
1524 	  st = QuoteExp.voidExp; // From #!void
1525         else if (st instanceof ValuesFromLList)
1526         {
1527           for (Object vs = ((ValuesFromLList) st).values;
1528                vs != LList.Empty; )
1529             {
1530               Pair p = (Pair) vs;
1531               Object save = pushPositionOf(p);
1532               scanForm(p.getCar(), defs);
1533               popPositionOf(save);
1534               vs = p.getCdr();
1535             }
1536         }
1537 	else
1538 	  {
1539 	    Object[] vals = ((Values) st).getValues();
1540 	    for (int i = 0;  i < vals.length;  i++)
1541 	      scanForm(vals[i], defs);
1542 	    return;
1543 	  }
1544       }
1545     if (st instanceof Pair)
1546       {
1547         Pair st_pair = (Pair) st;
1548         Declaration saveContext = macroContext;
1549         Syntax syntax = null;
1550         ScopeExp savedScope = current_scope;
1551         Object savedPosition = pushPositionOf(st);
1552         if (st instanceof SourceLocator && defs.getLineNumber() < 0)
1553           defs.setLocation((SourceLocator) st);
1554         try
1555           {
1556             Object obj = st_pair.getCar();
1557             if (obj instanceof SyntaxForm)
1558               {
1559                 SyntaxForm sf = (SyntaxForm) st_pair.getCar();
1560                 savedScope = setPushCurrentScope(sf.getScope());
1561                 obj = sf.getDatum();
1562               }
1563             Pair p;
1564             if (obj instanceof Pair
1565                 && (p = (Pair) obj).getCar() == LispLanguage.lookup_sym
1566                 && p.getCdr() instanceof Pair
1567                 && (p = (Pair) p.getCdr()).getCdr() instanceof Pair)
1568               {
1569                 Expression part1 = rewrite(p.getCar());
1570                 Expression part2 = rewrite_car_for_lookup((Pair) p.getCdr());
1571                 Object value1 = part1.valueIfConstant();
1572                 Object value2 = part2.valueIfConstant();
1573                 if (value1 instanceof Class && value2 instanceof Symbol)
1574                   {
1575                     try
1576                       {
1577                         obj = GetNamedPart.getNamedPart(value1, (Symbol)value2);
1578                         if (obj instanceof Syntax)
1579                           syntax = (Syntax) obj;
1580                       }
1581                     catch (Exception ex)
1582                       {
1583                         obj = null;
1584                       }
1585                   }
1586                 else
1587                   obj = namespaceResolve(part1, part2);
1588               }
1589             if (obj instanceof Symbol && ! selfEvaluatingSymbol(obj))
1590               {
1591                 Expression func = rewrite(obj, 'M');
1592                 if (func instanceof ReferenceExp)
1593                   {
1594                     Declaration decl = ((ReferenceExp) func).getBinding();
1595                     if (decl != null)
1596                       syntax = check_if_Syntax(decl);
1597                     else
1598                       {
1599                         obj = resolve(obj, true);
1600                         if (obj instanceof Syntax)
1601                           syntax = (Syntax) obj;
1602                       }
1603                   }
1604               }
1605             // Recognize deferred begin created in scanBody for pendingForms.
1606             // A seemingly-cleaner (obj instanceof Syntax) causes problems
1607             // with some Syntax forms, such as define.
1608             else if (obj == kawa.standard.begin.begin
1609                      || obj == kawa.standard.define_library.define_library_scan)
1610               syntax = (Syntax) obj;
1611           }
1612         finally
1613           {
1614               if (savedScope != current_scope)
1615                 setPopCurrentScope(savedScope);
1616             popPositionOf(savedPosition);
1617           }
1618 	if (syntax != null)
1619 	  {
1620 	    String save_filename = getFileName();
1621 	    try
1622 	      {
1623 		syntax.scanForm(st_pair, defs, this);
1624 		return;
1625 	      }
1626 	    finally
1627 	      {
1628                 macroContext = saveContext;
1629 	      }
1630 	  }
1631       }
1632     pushForm(st);
1633   }
1634 
1635   /** Recursive helper method for rewrite_body.
1636    * Scan body for definitions, adding partially macro-expanded
1637    * expressions into the <code>formStack</code>.
1638    * @param makeList if true, return a list representation of the scanned
1639    *   forms (not including declarations); else forms are push on formStack
1640    * @return a list of forms if <code>makeList</code> (possibly wrapped
1641    * in a <code>SyntaxForm</code>); otherwise <code>null</code>.
1642    */
1643 
1644   public LList scanBody (Object body, ScopeExp defs, boolean makeList)
1645   {
1646     LList list = makeList ? LList.Empty : null;
1647     Pair lastPair = null;
1648     while (body != LList.Empty)
1649       {
1650 	if (body instanceof SyntaxForm)
1651 	  {
1652 	    SyntaxForm sf = (SyntaxForm) body;
1653 	    ScopeExp save_scope = setPushCurrentScope(sf.getScope());
1654 	    try
1655 	      {
1656 		Pair first = formStack.last;
1657 
1658 		LList f = scanBody(sf.getDatum(), defs, makeList);
1659                 if (makeList)
1660                   {
1661                     f = (LList) SyntaxForms.fromDatumIfNeeded(f, sf);
1662                     if (lastPair == null)
1663 		      return f;
1664                     lastPair.setCdrBackdoor(f);
1665                     return list;
1666                   }
1667 		pushForm(wrapSyntax(popForms(first), sf));
1668 		return null;
1669 	      }
1670 	    finally
1671 	      {
1672 		setPopCurrentScope(save_scope);
1673 	      }
1674 	  }
1675 	else if (body instanceof Pair)
1676 	  {
1677 	    Pair pair = (Pair) body;
1678 	    Pair first = formStack.last;
1679             Object savePos = pushPositionOf(pair);
1680 	    scanForm(pair.getCar(), defs);
1681             popPositionOf(savePos);
1682             if (getState() == Compilation.PROLOG_PARSED && pendingForm != null)
1683               {
1684                 // We've seen a require form during the initial pass when
1685                 // we're looking module names.  Defer the require and any
1686                 // following forms in this body.
1687                 if (pair.getCar() != pendingForm)
1688                   pair = makePair(pair, pendingForm, pair.getCdr());
1689                 pendingForm = new Pair(kawa.standard.begin.begin, pair);
1690                 if (makeList)
1691                   formStack.pushAll(list);
1692                 return LList.Empty;
1693               }
1694 	    if (makeList)
1695 	      {
1696                 Pair last = formStack.lastPair();
1697                 LList nlist = (LList) formStack.popTail(first);
1698                 if (lastPair == null)
1699 		  list = nlist;
1700 		else
1701 		  lastPair.setCdrBackdoor(nlist);
1702                 if (last != first)
1703                   lastPair = last;
1704 	      }
1705 	    body = pair.getCdr();
1706 	  }
1707 	else
1708 	  {
1709 	    pushForm(syntaxError("body is not a proper list"));
1710 	    break;
1711 	  }
1712       }
1713     return list;
1714   }
1715 
1716   public static Pair makePair(Pair pair, Object car, Object cdr)
1717   {
1718     if (pair instanceof PairWithPosition)
1719       return new PairWithPosition((PairWithPosition) pair, car, cdr);
1720     return new Pair(car, cdr);
1721   }
1722 
1723   /**
1724    * Re-write a Scheme 'body' in S-expression format into internal form.
1725    */
1726 
1727   public Expression rewrite_body (Object exp)
1728   {
1729     // NOTE we have both a rewrite_body and a rewriteBody.
1730     // This is confusing, at the least.  FIXME.
1731     Object saved = pushPositionOf(exp);
1732     LetExp defs = new LetExp();
1733     defs.setFlag(LetExp.IS_BODY_SCOPE);
1734     int renamedAliasOldSize = renamedAliasCount();
1735     Pair first = formStack.last;
1736     defs.setOuter(current_scope);
1737     current_scope = defs;
1738     try
1739       {
1740         LList list = scanBody(exp, defs, true);
1741 	if (list.isEmpty())
1742 	  pushForm(syntaxError("body with no expressions"));
1743         int ndecls = 0;
1744         for (Declaration decl = defs.firstDecl(); decl != null; decl = decl.nextDecl())
1745           {
1746             if (! decl.getFlag(Declaration.IS_DYNAMIC))
1747               {
1748                 ndecls++;
1749                 decl.setInitValue(QuoteExp.undefined_exp);
1750               }
1751           }
1752         rewriteBody(list);
1753         int renamedAliasNewSize = renamedAliasCount();
1754         popRenamedAlias(renamedAliasNewSize - renamedAliasOldSize);
1755 	Expression body = makeBody(first, null);
1756 	setLineOf(body);
1757 	if (ndecls == 0)
1758 	  return body;
1759 	defs.setBody(body);
1760 	setLineOf(defs);
1761 	return defs;
1762       }
1763     finally
1764       {
1765 	pop(defs);
1766 	popPositionOf(saved);
1767       }
1768   }
1769 
1770   protected void rewriteBody (LList forms)
1771   {
1772     while (forms != LList.Empty)
1773       {
1774         Pair pair = (Pair) forms;
1775         Object saved = pushPositionOf(pair);
1776         try
1777           {
1778             rewriteInBody(pair.getCar());
1779           }
1780         finally
1781           {
1782             popPositionOf(saved);
1783           }
1784         forms = (LList) pair.getCdr();
1785       }
1786   }
1787 
1788   /** Combine a list of zero or more expression forms into a "body". */
1789   protected Expression makeBody(Pair head, ScopeExp scope)
1790   {
1791     Object tail = formStack.popTail(head);
1792     int nforms = LList.length(tail);
1793     if (nforms == 0)
1794       return QuoteExp.voidExp;
1795     Pair first = (Pair) tail;
1796      if (nforms == 1)
1797       {
1798 	return (Expression) first.getCar();
1799       }
1800     else
1801       {
1802 	Expression[] exps = new Expression[nforms];
1803         first.toArray(exps);
1804         if (scope instanceof ModuleExp)
1805 	  return new ApplyExp(gnu.kawa.functions.AppendValues.appendValues,
1806 			      exps);
1807 	else
1808 	  return makeBody(exps);
1809       }
1810   }
1811 
1812   public boolean appendBodyValues () { return false; }
1813 
1814   /** Combine a 'body' consisting of a list of expression. */
1815   public Expression makeBody(Expression[] exps)
1816   {
1817     if (appendBodyValues())
1818       return new ApplyExp(gnu.kawa.functions.AppendValues.appendValues, exps);
1819     else
1820       return new BeginExp (exps);
1821   }
1822 
1823   /** Storage used by noteAccess and processAccesses. */
1824   ArrayList notedAccess;
1825 
1826   /** Note that we reference name in a given scope.
1827    * This may be called when defining a macro, at scan-time,
1828    * and the name may be bound to a declaration we haven't seen yet. */
1829   public void noteAccess (Object name, ScopeExp scope)
1830   {
1831     if (notedAccess == null)
1832       notedAccess = new ArrayList();
1833     notedAccess.add(name);
1834     notedAccess.add(scope);
1835   }
1836 
1837   /** Check references recorded by noteAccess.
1838    * Resolve now to a Declaration, and note the access.
1839    * This is needed in case an exported macro references a private Declaration.
1840    */
1841   public void processAccesses ()
1842   {
1843     if (notedAccess == null)
1844       return;
1845     int sz = notedAccess.size();
1846     ScopeExp saveScope = current_scope;
1847     for (int i = 0;  i < sz;  i += 2)
1848       {
1849 	Object name = notedAccess.get(i);
1850 	ScopeExp scope = (ScopeExp) notedAccess.get(i+1);
1851 	if (current_scope != scope)
1852           {
1853             // I.e. first time do equivalent of setPushCurrentScope
1854             if (current_scope == saveScope)
1855               lexical.pushSaveTopLevelRedefs();
1856 	    setCurrentScope(scope);
1857           }
1858 	Declaration decl =  (Declaration) lexical.lookup(name, -1);
1859 	if (decl != null && ! decl.getFlag(Declaration.IS_UNKNOWN))
1860 	  {
1861             decl.getContext().currentLambda().capture(decl);
1862 	    decl.setCanRead(true);
1863             decl.setSimple(false);
1864 	    decl.setFlag(Declaration.EXTERNAL_ACCESS);
1865 	  }
1866       }
1867     if (current_scope != saveScope)
1868       setPopCurrentScope(saveScope);
1869   }
1870 
1871   public void finishModule(ModuleExp mexp)
1872   {
1873     boolean moduleStatic = mexp.isStatic();
1874     for (Declaration decl = mexp.firstDecl();
1875 	 decl != null;  decl = decl.nextDecl())
1876       {
1877 	if (decl.getFlag(Declaration.NOT_DEFINING))
1878 	  {
1879 	    String msg1 = "'";
1880 	    String msg2
1881 	      = (decl.getFlag(Declaration.EXPORT_SPECIFIED)
1882 		 ? "' exported but never defined"
1883 		 : decl.getFlag(Declaration.STATIC_SPECIFIED)
1884 		 ? "' declared static but never defined"
1885 		 : "' declared but never defined");
1886 	    error('e', decl, msg1, msg2);
1887 	  }
1888 	if (mexp.getFlag(ModuleExp.EXPORT_SPECIFIED)
1889             || (generateMainMethod() && ! immediate))
1890 	  {
1891 	    if (decl.getFlag(Declaration.EXPORT_SPECIFIED))
1892 	      {
1893 		if (decl.isPrivate())
1894 		  {
1895 		    if (decl.getFlag(Declaration.PRIVATE_SPECIFIED))
1896 		      error('e', decl,
1897 			    "'", "' is declared both private and exported");
1898 		    decl.setPrivate(false);
1899 		  }
1900 	      }
1901 	    else if (! kawa.standard.IfFeature.isProvide(decl))
1902 	      decl.setPrivate(true);
1903 	  }
1904 	if (moduleStatic)
1905 	  decl.setFlag(Declaration.STATIC_SPECIFIED);
1906 	else if ((mexp.getFlag(ModuleExp.NONSTATIC_SPECIFIED)
1907 		  && ! decl.getFlag(Declaration.STATIC_SPECIFIED))
1908 		 || gnu.expr.Compilation.moduleStatic < 0
1909 		 || mexp.getFlag(ModuleExp.SUPERTYPE_SPECIFIED))
1910 	  decl.setFlag(Declaration.NONSTATIC_SPECIFIED);
1911       }
1912     if (mexp.getFlag(ModuleExp.SUPERTYPE_SPECIFIED))
1913         mexp.setFlag(false, ModuleExp.USE_DEFINED_CLASS);
1914   }
1915 
1916   public void resolveModule(ModuleExp mexp)
1917   {
1918     Expression savePos = new ReferenceExp((Object) null);
1919     int numPending = pendingImports == null ? 0 : pendingImports.size();
1920     for (int i = 0;  i < numPending;  )
1921       {
1922         ModuleInfo info = (ModuleInfo) pendingImports.elementAt(i++);
1923         ScopeExp defs = (ScopeExp) pendingImports.elementAt(i++);
1924         Expression posExp = (Expression) pendingImports.elementAt(i++);
1925         Pair beforeGoal = (Pair) pendingImports.elementAt(i++);
1926         DeclSetMapper mapper = (DeclSetMapper) pendingImports.elementAt(i++);
1927         if (mexp == defs)
1928           {
1929             // process(BODY_PARSED);
1930             savePos.setLine(this);
1931             setLine(posExp);
1932             Pair beforeImports = formStack.last;
1933             kawa.standard.require.importDefinitions(null, info, mapper,
1934                                                     formStack, defs, this);
1935             if (beforeGoal != beforeImports
1936                 && beforeImports != formStack.last)
1937               {
1938                 // Move forms derived from the import forwards in the list,
1939                 // just following beforeGoal.
1940                 Object firstGoal = beforeGoal.getCdr();
1941                 Object firstImports = beforeImports.getCdr();
1942                 beforeGoal.setCdrBackdoor(firstImports);
1943                 formStack.last.setCdrBackdoor(firstGoal);
1944                 beforeImports.setCdrBackdoor(LList.Empty);
1945                 formStack.last = beforeImports;
1946               }
1947             setLine(savePos);
1948           }
1949       }
1950     pendingImports = null;
1951     setModule(mexp);
1952 
1953     savePos.setLine(this);
1954     setLine(null, -1, -1);
1955     Compilation save_comp = Compilation.setSaveCurrent(this);
1956     try
1957       {
1958         Pair firstForm = formStack.getHead();
1959         rewriteBody((LList) formStack.popTail(firstForm));
1960 	mexp.body = makeBody(firstForm, mexp);
1961 
1962         processAccesses();
1963 
1964         // In immediate mode need to preserve Declaration for current "session".
1965         if (! immediate)
1966 	  lexical.pop(mexp);
1967 
1968         // Patch up renamed exports - see export.
1969         for (Declaration decl = mexp.firstDecl();  decl != null;
1970              decl = decl.nextDecl()) {
1971             if (decl.getSymbol() == null
1972                 && decl.getFlag(Declaration.EXPORT_SPECIFIED)) {
1973                 decl.patchSymbolFromSet();
1974             }
1975         }
1976       }
1977     finally
1978       {
1979 	Compilation.restoreCurrent(save_comp);
1980         setLine(savePos);
1981       }
1982 
1983     /* DEBUGGING:
1984     OutPort err = OutPort.errDefault ();
1985     err.print ("[Re-written expression for load/compile: ");
1986     mexp.print (err);
1987     //err.print ("\nbefore load<"+mod.getClass().getName()+">");
1988     err.println();
1989     err.flush();
1990     */
1991   }
1992 
1993   public Declaration makeRenamedAlias (Declaration decl,
1994 				       ScopeExp templateScope)
1995   {
1996     if (templateScope == null)
1997       return decl; // ???
1998     return makeRenamedAlias(decl.getSymbol(), decl, templateScope);
1999   }
2000 
2001   public Declaration makeRenamedAlias (Object name,
2002 				       Declaration decl,
2003 				       ScopeExp templateScope)
2004   {
2005     Declaration alias = new Declaration(name);
2006     alias.setAlias(true);
2007     alias.setPrivate(true);
2008     alias.context = templateScope;
2009     ReferenceExp ref = new ReferenceExp(decl);
2010     ref.setDontDereference(true);
2011     alias.noteValue(ref);
2012     return alias;
2013   }
2014 
2015   /** Push an alias for a declaration in a scope.
2016    * If the name of {@code decl} came from a syntax template
2017    * whose immediate scope is {@code templateScope},
2018    * then the same syntax template may contain local variable references
2019    * that are also in the same {@code templateScope}.
2020    * Such variable references will <em>not</em> look in the current
2021    * "physical" scope, where we just created {@code decl}, but
2022    * will instead search the "lexical" {@code templateScope}.
2023    * So that such references can resolve to {@code decl}, we
2024    * create an alias in {@code templateScope} that points
2025    * to {@code decl}.  We record that we did this in the
2026    * {@code renamedAliasStack}, so we can remove the alias later.
2027    */
2028   public void pushRenamedAlias (Declaration alias)
2029   {
2030     Declaration decl = getOriginalRef(alias).getBinding();
2031     ScopeExp templateScope = alias.context;
2032     decl.setSymbol(null);
2033     Declaration old = templateScope.lookup(alias.getSymbol());
2034     if (old != null)
2035       templateScope.remove(old);
2036     templateScope.addDeclaration(alias);
2037     if (renamedAliasStack == null)
2038       renamedAliasStack = new Stack<Declaration>();
2039     renamedAliasStack.push(old);
2040     renamedAliasStack.push(alias);
2041   }
2042 
2043     public int renamedAliasCount() {
2044         return renamedAliasStack == null ? 0 : renamedAliasStack.size() >> 1;
2045     }
2046 
2047   /** Remove one or more aliases created by <code>pushRenamedAlias</code>. */
2048   public void popRenamedAlias (int count)
2049   {
2050     while (--count >= 0)
2051       {
2052 	Declaration alias = (Declaration) renamedAliasStack.pop();
2053         ScopeExp templateScope = alias.getContext();
2054 	Declaration decl = getOriginalRef(alias).getBinding();
2055 	decl.setSymbol(alias.getSymbol());
2056 	templateScope.remove(alias);
2057 	Declaration old = renamedAliasStack.pop();
2058 	if (old != null)
2059 	  templateScope.addDeclaration(old);
2060       }
2061   }
2062 
2063     public Declaration define(Object name, ScopeExp defs) {
2064         return define(name, (TemplateScope) null, defs);
2065     }
2066 
2067     public Declaration define(Object name, SyntaxForm nameSyntax,
2068                               ScopeExp defs) {
2069         return define(name, nameSyntax == null ? null : nameSyntax.getScope(),
2070                       defs);
2071     }
2072 
2073     public Declaration define(Object name, TemplateScope templateScope,
2074                               ScopeExp defs) {
2075         ScopeExp scope = templateScope != null ? templateScope
2076             : currentScope();
2077         boolean aliasNeeded = scope != defs;
2078         Object declName = aliasNeeded
2079             ? Symbol.makeUninterned(name.toString())
2080             : name;
2081         Declaration decl = defs.getDefine(declName, this);
2082         if (aliasNeeded) {
2083             Declaration alias = makeRenamedAlias(name, decl, scope);
2084             if (defs instanceof LetExp)
2085                 pushRenamedAlias(alias);
2086             else
2087                 scope.addDeclaration(alias);
2088         }
2089         push(decl);
2090         return decl;
2091     }
2092 
2093   static boolean isObjectSyntax (ClassType declaringClass, String fieldName)
2094   {
2095     return "objectSyntax".equals(fieldName)
2096       &&  "kawa.standard.object".equals(declaringClass.getName());
2097   }
2098 
2099     public FormStack formStack = new FormStack(this);
2100     public void pushForm(Object value) { formStack.push(value); }
2101 
2102     /** A list of "forms" to be further processed.
2103      * It is implemented as an LList so we can save position information.
2104      */
2105     public static class FormStack extends Pair {
2106         private Pair last = this;
2107         SourceLocator sloc;
2108 
2109         public FormStack(SourceLocator sloc) {
2110             this.sloc = sloc;
2111             this.cdr = LList.Empty;
2112         }
2113 
2114         /** Return the "head" of the list.
2115          * The cdr of the head is the first element.
2116          */
2117         public Pair getHead() { return this; }
2118         public Object getFirst() { return cdr; }
2119         /** The Pair whose car is the last form in the list.
2120          * If the list is empty, this returns the list head.
2121          */
2122         @Override
2123         public Pair lastPair() { return last; }
2124 
2125         /* DEBUGGING:
2126         public void dump() {
2127             int i=0;
2128             System.err.println("formStack len:"+LList.length(getFirst()));
2129             for(Object x = getFirst(); x instanceof Pair; i++) {
2130                 Pair p = (Pair) x;
2131                 //if (! (p.getCar() instanceof SetExp))
2132                     System.err.println("- #"+i+": "+p.getCar());
2133                 x = p.getCdr();
2134             }
2135         }
2136         */
2137 
2138         public Object popTail(Pair oldTail) {
2139             Object r = oldTail.getCdr();
2140             oldTail.setCdrBackdoor(LList.Empty);
2141             last = oldTail;
2142             return r;
2143         }
2144 
2145         public void push(Object value) {
2146             PairWithPosition pair = new PairWithPosition(sloc, value, LList.Empty);
2147             last.setCdrBackdoor(pair);
2148             last = pair;
2149         }
2150 
2151         public void pushAll(LList values) {
2152             if (values == LList.Empty)
2153                 return;
2154             last.setCdrBackdoor(values);
2155             last = ((Pair) values).lastPair();
2156         }
2157 
2158         public void pushAll(LList values, Pair valuesLast) {
2159             if (values == LList.Empty)
2160                 return;
2161             last.setCdrBackdoor(values);
2162             last = valuesLast;
2163         }
2164 
2165         public void pushAfter(Object value, Pair position) {
2166             Pair pair = new PairWithPosition(sloc, value, position.getCdr());
2167             position.setCdrBackdoor(pair);
2168             if (last == position)
2169                 last = pair;
2170         }
2171     }
2172 
2173     /** An implementationof Values using a linked list.
2174      */
2175     public static class ValuesFromLList extends Values.FromList<Object> {
2176         public LList values;
2177 
2178         public ValuesFromLList(LList values) {
2179             super(values);
2180             this.values = values;
2181         }
2182     }
2183 
2184     Stack<ScanContext> scanContextStack = new Stack<ScanContext>();
2185 
2186     public ScanContext getScanContext() { return scanContextStack.peek(); }
2187     public int curScanNesting() { return scanContextStack.size(); }
2188     public Stack<ScanContext> getScanContextStack() { return scanContextStack; }
2189 
2190     public void pushScanContext (LambdaExp lambda) {
2191         ScanContext newContext = new ScanContext();
2192         newContext.lambda = lambda;
2193         scanContextStack.push(newContext);
2194     }
2195     public void popScanContext() {
2196         scanContextStack.pop();
2197     }
2198     public static class ScanContext {
2199         LinkedHashMap<Declaration,Declaration> decls
2200             = new LinkedHashMap<Declaration,Declaration>();
2201         ArrayList<Expression> scanExpressions = null;
2202         LambdaExp lambda;
2203 
2204         public LambdaExp getLambda() { return lambda; }
2205 
2206         public Declaration addSeqDecl(Declaration scanVar) {
2207             Declaration param = decls.get(scanVar);
2208             if (param == null) {
2209                 param = lambda.addParameter(null);
2210                 decls.put(scanVar, param);
2211             }
2212             return param;
2213         }
2214         public void addSeqExpression(Expression scanExp) {
2215             if (scanExpressions == null)
2216                 scanExpressions = new ArrayList<Expression>();
2217             scanExpressions.add(scanExp);
2218         }
2219     }
2220 }
2221