Initial commit
[profile/ivi/openjade.git] / style / Expression.cxx
1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
3
4 #include "stylelib.h"
5 #include "Insn.h"
6 #include "Insn2.h"
7 #include "Interpreter.h"
8 #include "InterpreterMessages.h"
9 #include "ELObjMessageArg.h"
10 #include "Expression.h"
11 #include "Style.h"
12 #include "macros.h"
13
14 #ifdef DSSSL_NAMESPACE
15 namespace DSSSL_NAMESPACE {
16 #endif
17
18 Expression::Expression(const Location &loc)
19 : loc_(loc)
20 {
21 }
22
23 void Expression::optimize(Interpreter &, const Environment &, Owner<Expression> &)
24 {
25 }
26
27 ELObj *Expression::constantValue() const
28 {
29   return 0;
30 }
31
32 const Identifier *Expression::keyword() const
33 {
34   return 0;
35 }
36
37 void Expression::markBoundVars(BoundVarList &, bool)
38 {
39 }
40
41 ConstantExpression::ConstantExpression(ELObj *obj, const Location &loc)
42 : Expression(loc), obj_(obj)
43 {
44 }
45
46 InsnPtr
47 ConstantExpression::compile(Interpreter &interp, const Environment &env,
48                             int stackPos, const InsnPtr &next)
49 {
50   return new ConstantInsn(obj_, new ResolveQuantitiesInsn(location(), next));
51 }
52
53 void ConstantExpression::optimize(Interpreter &interp, const Environment &,
54                                   Owner<Expression> &expr)
55 {
56   ELObj *tem = obj_->resolveQuantities(0, interp, location());
57   if (tem) {
58     interp.makePermanent(tem);
59     expr = new ResolvedConstantExpression(tem, location());
60   }
61 }
62
63 bool ConstantExpression::canEval(bool) const
64 {
65   return 0;
66 }
67
68 const Identifier *ConstantExpression::keyword() const
69 {
70   const KeywordObj *k = obj_->asKeyword();
71   if (k)
72     return k->identifier();
73   else
74     return 0;
75 }
76
77 ResolvedConstantExpression::ResolvedConstantExpression(ELObj *obj, const Location &loc)
78 : Expression(loc), obj_(obj)
79 {
80 }
81
82 InsnPtr
83 ResolvedConstantExpression::compile(Interpreter &interp, const Environment &env,
84                                     int stackPos, const InsnPtr &next)
85 {
86   return new ConstantInsn(obj_, next);
87 }
88
89 ELObj *ResolvedConstantExpression::constantValue() const
90 {
91   return obj_;
92 }
93
94 bool ResolvedConstantExpression::canEval(bool) const
95 {
96   return 1;
97 }
98
99 CallExpression::CallExpression(Owner<Expression> &op,
100                                NCVector<Owner<Expression> > &args,
101                                const Location &loc)
102 : Expression(loc)
103 {
104   op.swap(op_);
105   args.swap(args_);
106 }
107
108 bool CallExpression::canEval(bool) const
109 {
110   if (!op_->canEval(1))
111     return 0;
112   for (size_t i = 0; i < args_.size(); i++)
113     if (!args_[i]->canEval(1))
114       return 0;
115   return 1;
116 }
117
118 int CallExpression::nArgs()
119 {
120   return args_.size();
121 }
122
123 InsnPtr CallExpression::compile(Interpreter &interp, const Environment &env,
124                                 int stackPos, const InsnPtr &next)
125 {
126   op_->optimize(interp, env, op_);
127   ELObj *value = op_->constantValue();
128   InsnPtr result;
129   if (value) {
130     FunctionObj *func = value->asFunction();
131     if (!func) {
132       interp.setNextLocation(location());
133       interp.message(InterpreterMessages::callNonFunction,
134                      ELObjMessageArg(value, interp));
135       return new ErrorInsn;
136     }
137     if (nArgs() < func->nRequiredArgs()) {
138       interp.setNextLocation(location());
139       interp.message(InterpreterMessages::missingArg);
140       return new ErrorInsn;
141     }
142     if (nArgs() - func->nRequiredArgs() > func->nOptionalArgs()) {
143       if (func->nKeyArgs()) {
144         if ((nArgs() - func->nRequiredArgs() - func->nOptionalArgs()) & 1) {
145           interp.setNextLocation(location());
146           interp.message(InterpreterMessages::oddKeyArgs);
147           args_.resize(func->nRequiredArgs() + func->nOptionalArgs());
148         }
149       }
150       else if (!func->restArg()) {
151         interp.setNextLocation(location());
152         interp.message(InterpreterMessages::tooManyArgs);
153         args_.resize(func->nRequiredArgs() + func->nOptionalArgs());
154       }
155     }
156
157     int callerArgs;
158     if (!next.isNull() && next->isReturn(callerArgs) && !interp.debugMode())
159       result = func->makeTailCallInsn(nArgs(), interp, location(), callerArgs);
160     else
161       result = func->makeCallInsn(nArgs(), interp, location(), next);
162   }
163   else {
164     int n = nArgs();
165     int callerArgs;
166     if (!next.isNull() && next->isReturn(callerArgs) && !interp.debugMode())
167       result = new TailApplyInsn(callerArgs, n, location());
168     else
169       result = new ApplyInsn(n, location(), next);
170     result = op_->compile(interp, env, stackPos + n, result);
171   }
172   for (size_t i = args_.size(); i > 0; i--)
173     result = optimizeCompile(args_[i - 1], interp, env,
174                              stackPos + i - 1, result);
175   return result;
176 }
177
178 void CallExpression::markBoundVars(BoundVarList &vars, bool shared)
179 {
180   op_->markBoundVars(vars, shared);
181   for (size_t i = 0; i < args_.size(); i++)
182     args_[i]->markBoundVars(vars, shared);
183 }
184
185 VariableExpression::VariableExpression(const Identifier *ident,
186                                        const Location &loc)
187 : Expression(loc), ident_(ident), isTop_(0)
188 {
189 }
190
191 InsnPtr VariableExpression::compile(Interpreter &interp,
192                                     const Environment &env,
193                                     int stackPos,
194                                     const InsnPtr &next)
195 {
196   bool isFrame;
197   int index;
198   unsigned flags;
199   if (env.lookup(ident_, isFrame, index, flags)) {
200     bool boxed = BoundVar::flagsBoxed(flags);
201     InsnPtr tem;
202     int n;
203     if (isFrame
204         && !next.isNull()
205         && next->isPopBindings(n, tem)
206         && n == 1
207         && index - stackPos == -1) {
208       if (flags & BoundVar::uninitFlag)
209         tem = new CheckInitInsn(ident_, location(), tem);
210       // This happens with named let.
211       if (boxed)
212         return new UnboxInsn(tem);
213       else
214         return tem;
215     }
216     if (flags & BoundVar::uninitFlag)
217       tem = new CheckInitInsn(ident_, location(), next);
218     else
219       tem = next;
220     if (boxed)
221       tem = new UnboxInsn(tem);
222     if (isFrame)
223       return new StackRefInsn(index - stackPos, index, tem);
224     else
225       return new ClosureRefInsn(index, tem);
226   }
227   isTop_ = 1;
228   Location loc;
229   unsigned part;
230   if (!ident_->defined(part, loc)) {
231     interp.setNextLocation(location());
232     interp.message(InterpreterMessages::undefinedVariableReference,
233                    StringMessageArg(ident_->name()));
234     return new ErrorInsn;
235   }
236   ELObj *val = ident_->computeValue(0, interp);
237   if (!val)
238     return new TopRefInsn(ident_, next);
239   if (interp.isError(val))
240     return new ErrorInsn;
241   return new ConstantInsn(val, next);
242 }
243
244 void VariableExpression::optimize(Interpreter &interp, const Environment &env,
245                                   Owner<Expression> &expr)
246 {
247   bool isFrame;
248   int index;
249   unsigned flags;
250   if (env.lookup(ident_, isFrame, index, flags))
251     return;
252   isTop_ = 1;
253   Location loc;
254   unsigned part;
255   if (ident_->defined(part, loc)) {
256     ELObj *obj = ident_->computeValue(0, interp);
257     if (obj && !interp.isError(obj)) {
258       interp.makePermanent(obj);
259       expr = new ConstantExpression(obj, location());
260       expr->optimize(interp, env, expr);
261     }
262   }
263 }
264
265 bool VariableExpression::canEval(bool) const
266 {
267   return !isTop_ || ident_->evaluated();
268 }
269
270 void VariableExpression::markBoundVars(BoundVarList &vars, bool shared)
271 {
272   vars.mark(ident_, BoundVar::usedFlag | (shared ? BoundVar::sharedFlag : 0));
273 }
274
275 IfExpression::IfExpression(Owner<Expression> &test,
276                            Owner<Expression> &consequent,
277                            Owner<Expression> &alternate,
278                            const Location &loc)
279 : Expression(loc)
280 {
281   test.swap(test_);
282   consequent.swap(consequent_);
283   alternate.swap(alternate_);
284 }
285
286 bool IfExpression::canEval(bool maybeCall) const
287 {
288   return (test_->canEval(maybeCall)
289           && consequent_->canEval(maybeCall)
290           && alternate_->canEval(maybeCall));
291 }
292
293 void IfExpression::optimize(Interpreter &interp, const Environment &env,
294                             Owner<Expression> &expr)
295 {
296   test_->optimize(interp, env, test_);
297   ELObj *obj = test_->constantValue();
298   if (obj) {
299     if (obj->isTrue()) {
300       expr = consequent_.extract();
301       expr->optimize(interp, env, expr);
302     }
303     else {
304       expr = alternate_.extract();
305       expr->optimize(interp, env, expr);
306     }
307   }
308 }
309
310 InsnPtr IfExpression::compile(Interpreter &interp, const Environment &env,
311                               int stackPos, const InsnPtr &next)
312 {
313   alternate_->optimize(interp, env, alternate_);
314   if (alternate_->constantValue() == interp.makeFalse())
315     return test_->compile(interp, env, stackPos,
316                           new AndInsn(optimizeCompile(consequent_,
317                                                       interp, env,
318                                                       stackPos, next),
319                                       next));
320   else
321     return test_->compile(interp, env, stackPos,
322                           new TestInsn(optimizeCompile(consequent_,
323                                                        interp, env,
324                                                        stackPos, next),
325                                        alternate_->compile(interp, env,
326                                                            stackPos, next)));
327 }
328
329 void IfExpression::markBoundVars(BoundVarList &vars, bool shared)
330 {
331   test_->markBoundVars(vars, shared);
332   consequent_->markBoundVars(vars, shared);
333   alternate_->markBoundVars(vars, shared);
334 }
335
336 OrExpression::OrExpression(Owner<Expression> &test1,
337                            Owner<Expression> &test2,
338                            const Location &loc)
339 : Expression(loc)
340 {
341   test1.swap(test1_);
342   test2.swap(test2_);
343 }
344
345 bool OrExpression::canEval(bool maybeCall) const
346 {
347   return (test1_->canEval(maybeCall)
348           && test2_->canEval(maybeCall));
349 }
350
351 void OrExpression::optimize(Interpreter &interp, const Environment &env,
352                             Owner<Expression> &expr)
353 {
354   test1_->optimize(interp, env, test1_);
355   ELObj *obj = test1_->constantValue();
356   if (obj) {
357     if (obj->isTrue())
358       expr = test1_.extract();
359     else {
360       expr = test2_.extract();
361       expr->optimize(interp, env, expr);
362     }
363   }
364 }
365
366 InsnPtr OrExpression::compile(Interpreter &interp, const Environment &env,
367                               int stackPos, const InsnPtr &next)
368 {
369   return test1_->compile(interp, env, stackPos,
370                          new OrInsn(optimizeCompile(test2_, interp, env,
371                                                     stackPos, next),
372                                     next));
373 }
374
375 void OrExpression::markBoundVars(BoundVarList &vars, bool shared)
376 {
377   test1_->markBoundVars(vars, shared);
378   test2_->markBoundVars(vars, shared);
379 }
380
381 CondFailExpression::CondFailExpression(const Location &loc)
382 : Expression(loc)
383 {
384 }
385
386 InsnPtr CondFailExpression::compile(Interpreter &, const Environment &,
387                                     int, const InsnPtr &)
388 {
389   return new CondFailInsn(location());
390 }
391
392 bool CondFailExpression::canEval(bool maybeCall) const
393 {
394   return 1;
395 }
396
397 CaseExpression::CaseExpression(Owner<Expression> &key,
398                                NCVector<Case> &cases,
399                                Owner<Expression> &elseClause,
400                                const Location &loc)
401 : Expression(loc)
402 {
403   key.swap(key_);
404   cases.swap(cases_);
405   elseClause.swap(else_);
406 }
407
408 InsnPtr CaseExpression::compile(Interpreter &interp,
409                                 const Environment &env, int stackPos,
410                                 const InsnPtr &next)
411 {
412   InsnPtr finish;
413   if (else_)
414     finish = new PopInsn(else_->compile(interp, env, stackPos, next));
415   else
416     finish = new CaseFailInsn(location());
417   for (size_t i = 0; i < cases_.size(); i++) {
418     InsnPtr match = cases_[i].expr->compile(interp, env, stackPos, next);
419     for (size_t j = 0; j < nResolved_[i]; j++)
420       finish = new CaseInsn(cases_[i].datums[j], match, finish);
421   }
422   // FIXME handle unresolved quantities
423   return key_->compile(interp, env, stackPos, finish);
424 }
425
426 void CaseExpression::markBoundVars(BoundVarList &vars, bool shared)
427 {
428   key_->markBoundVars(vars, shared);
429   for (size_t i = 0; i < cases_.size(); i++)
430     cases_[i].expr->markBoundVars(vars, shared);
431   if (else_)
432     else_->markBoundVars(vars, shared);
433 }
434
435 bool CaseExpression::canEval(bool maybeCall) const
436 {
437   if (!key_->canEval(maybeCall))
438     return 0;
439   if (else_ && !else_->canEval(maybeCall))
440     return 0;
441   for (size_t i = 0; i < cases_.size(); i++) {
442     if (!cases_[i].expr->canEval(maybeCall))
443       return 0;
444     if (nResolved_[i] == cases_[i].datums.size())
445       return 0;
446   }
447   return 1;
448 }
449
450 void CaseExpression::optimize(Interpreter &interp, const Environment &env,
451                               Owner<Expression> &expr)
452 {
453   key_->optimize(interp, env, key_);
454   ELObj *k = key_->constantValue();
455   nResolved_.assign(cases_.size(), 0);
456   bool unresolved = 0;
457   for (size_t i = 0; i < cases_.size(); i++) {
458     cases_[i].expr->optimize(interp, env, cases_[i].expr);
459     int nResolved = 0;
460     for (size_t j = 0; j < cases_[i].datums.size(); j++) {
461       ELObj *tem = cases_[i].datums[j]->resolveQuantities(0, interp,
462                                                           location());
463       if (tem) {
464         if (k && ELObj::eqv(*k, *tem)) {
465           expr = cases_[i].expr.extract();
466           return;
467         }
468         if (j != nResolved)
469           cases_[i].datums[j] = cases_[i].datums[nResolved];
470         cases_[i].datums[nResolved++] = tem;
471       }
472       else
473         unresolved = 1;
474     }
475     nResolved_[i] = nResolved;
476   }
477   if (else_) {
478     else_->optimize(interp, env, else_);
479     if (k && !unresolved)
480       expr = else_.extract();
481   }
482   else if (k && !unresolved) {
483     interp.setNextLocation(location());
484     interp.message(InterpreterMessages::caseFail, ELObjMessageArg(k, interp));
485   }
486   if (unresolved) {
487     interp.setNextLocation(location());
488     interp.message(InterpreterMessages::caseUnresolvedQuantities);
489   }
490 }
491
492
493 LambdaExpression::LambdaExpression(Vector<const Identifier *> &formals,
494                                    NCVector<Owner<Expression> > &inits,
495                                    int nOptional,
496                                    bool hasRest,
497                                    int nKey,
498                                    Owner<Expression> &body,
499                                    const Location &loc)
500 : Expression(loc)
501 {
502   formals.swap(formals_);
503   inits.swap(inits_);
504   body.swap(body_);
505   sig_.nRequiredArgs = formals_.size() - nOptional - nKey - hasRest;
506   sig_.nOptionalArgs = nOptional;
507   sig_.restArg = hasRest;
508   sig_.nKeyArgs = nKey;
509   sig_.keys = formals_.begin() + formals_.size() - nKey;
510 }
511
512 bool LambdaExpression::canEval(bool maybeCall) const
513 {
514   if (!maybeCall)
515     return 1;
516   if (!body_->canEval(1))
517     return 0;
518   for (size_t i = 0; i < inits_.size(); i++)
519     if (inits_[i] && !inits_[i]->canEval(1))
520       return 0;
521   return 1;
522 }
523
524 InsnPtr LambdaExpression::compile(Interpreter &interp, const Environment &env,
525                                   int stackPos, const InsnPtr &next)
526 {
527   BoundVarList boundVars;
528   env.boundVars(boundVars);
529   markBoundVars(boundVars, 0);
530   boundVars.removeUnused();
531   BoundVarList formalVars(formals_, sig_.nRequiredArgs);
532   for (int i = 0; i < sig_.nOptionalArgs + sig_.nKeyArgs; i++) {
533     if (inits_[i])
534       inits_[i]->markBoundVars(formalVars, 0);
535     formalVars.append(formals_[sig_.nRequiredArgs + i], 0);
536   }
537   if (sig_.restArg)
538     formalVars.append(formals_.back(), 0);
539   ASSERT(formalVars.size() == formals_.size());
540   body_->markBoundVars(formalVars, 0);
541   InsnPtr code
542     = optimizeCompile(body_, interp,
543                       Environment(formalVars, boundVars), formals_.size(),
544                       new ReturnInsn(formals_.size()));
545   if (sig_.nOptionalArgs || sig_.restArg || sig_.nKeyArgs) {
546     Vector<InsnPtr> entryPoints(sig_.nOptionalArgs
547                                 + (sig_.restArg || sig_.nKeyArgs)
548                                 + 1);
549     // First entry point is for only required args supplied
550     // Next entry is for one optional arg supplied, no rest arg
551     // Next entry is for two optional args, no rest arg
552     // ..
553     // Next entry is for all optional args, no other args
554     // Last entry is for all optional args supplied, and other args
555     //  (for this entry point all args are pushed; unspecified
556     //   keyword args are bound to 0).
557     entryPoints.back() = code;
558     // Box the rest arg if necessary.
559     if (sig_.restArg && formalVars.back().boxed())
560       entryPoints.back() = new BoxStackInsn(-1 - sig_.nKeyArgs, entryPoints.back());
561     if (sig_.nKeyArgs) {
562       // For each keyword argument test whether it is 0,
563       // and if so initialize it.
564       for (int i = sig_.nOptionalArgs + sig_.nKeyArgs - 1;
565            i >= sig_.nOptionalArgs;
566            i--) {
567         int offset = i - (sig_.nOptionalArgs + sig_.nKeyArgs);
568         InsnPtr &next = entryPoints.back();
569         InsnPtr set(new SetKeyArgInsn(offset, next));
570         if (formalVars[sig_.nRequiredArgs + i].boxed())
571           set = new BoxInsn(set);
572         if (inits_[i]) {
573           BoundVarList f(formalVars);
574           f.resize(sig_.nRequiredArgs + i + sig_.restArg);
575           set = optimizeCompile(inits_[i], interp,
576                                 Environment(f, boundVars),
577                                 formals_.size(),
578                                 set);
579         }
580         else
581           set = new ConstantInsn(interp.makeFalse(), set);
582         next = new TestNullInsn(offset, set, next);
583       }
584     }
585     if (sig_.restArg || sig_.nKeyArgs) {
586       for (int i = sig_.nOptionalArgs + sig_.nKeyArgs - 1;
587            i >= sig_.nOptionalArgs;
588            i--) {
589         if (formalVars[sig_.nRequiredArgs + i].boxed())
590           code = new BoxInsn(code);
591         if (inits_[i]) {
592           BoundVarList f(formalVars);
593           f.resize(sig_.nRequiredArgs + i + sig_.restArg);
594           code = optimizeCompile(inits_[i], interp,
595                                  Environment(f, boundVars),
596                                  f.size(),
597                                  code);
598         }
599         else
600           code = new ConstantInsn(interp.makeFalse(), code);
601       }
602       if (sig_.restArg) {
603         if (formalVars.back().boxed())
604           code = new BoxInsn(code);
605         code = new ConstantInsn(interp.makeNil(), code);
606       }
607       entryPoints[sig_.nOptionalArgs] = code;
608     }
609     for (int i = sig_.nOptionalArgs - 1; i >= 0; i--) {
610       InsnPtr tem(entryPoints[i + 1]);
611       if (formalVars[sig_.nRequiredArgs + i].boxed())
612         tem = new BoxInsn(tem);
613       if (inits_[i]) {
614         BoundVarList f(formalVars);
615         f.resize(sig_.nRequiredArgs + i);
616         entryPoints[i]
617           = optimizeCompile(inits_[i], interp,
618                             Environment(f, boundVars),
619                             f.size(),
620                             tem);
621       }
622       else
623         entryPoints[i] = new ConstantInsn(interp.makeFalse(),
624                                           tem);
625     }
626     for (int i = 0; i < sig_.nOptionalArgs; i++) {
627       if (formalVars[sig_.nRequiredArgs + i].boxed()) {
628         for (int j = i; j < sig_.nOptionalArgs; j++)
629           entryPoints[j + 1] = new BoxArgInsn(i + sig_.nRequiredArgs, entryPoints[j + 1]);
630         if (sig_.nKeyArgs || sig_.restArg)
631           entryPoints.back() = new BoxStackInsn(i - sig_.nKeyArgs - sig_.restArg
632                                                 - sig_.nOptionalArgs,
633                                                 entryPoints.back());
634       }
635     }
636     code = new VarargsInsn(sig_, entryPoints, location());
637   }
638   for (int i = 0; i < sig_.nRequiredArgs; i++)
639     if (formalVars[i].boxed())
640       code = new BoxArgInsn(i, code);
641   return compilePushVars(interp, env, stackPos, boundVars, 0,
642                          new ClosureInsn(&sig_, code,
643                                          boundVars.size(), next));
644 }
645
646 InsnPtr Expression::compilePushVars(Interpreter &interp,
647                                     const Environment &env,
648                                     int stackPos,
649                                     const BoundVarList &vars,
650                                     size_t varIndex,
651                                     const InsnPtr &next)
652 {
653   if (varIndex >= vars.size())
654     return next;
655   bool isFrame;
656   int index;
657   unsigned flags;
658   if (!env.lookup(vars[varIndex].ident, isFrame, index, flags))
659     CANNOT_HAPPEN();
660   if (isFrame)
661     return new FrameRefInsn(index,
662                             compilePushVars(interp, env, stackPos + 1, vars,
663                                             varIndex + 1, next));
664   else
665     return new ClosureRefInsn(index,
666                               compilePushVars(interp, env, stackPos + 1, vars,
667                                               varIndex + 1, next));
668 }
669
670 void LambdaExpression::markBoundVars(BoundVarList &vars, bool shared)
671 {
672   for (int i = 0; i < sig_.nOptionalArgs + sig_.nKeyArgs; i++)
673     if (inits_[i]) {
674       Vector<const Identifier *> f(formals_);
675       f.resize(sig_.nRequiredArgs + i
676                + (sig_.restArg && i >= sig_.nOptionalArgs));
677       vars.rebind(f);
678       inits_[i]->markBoundVars(vars, 1);
679       vars.unbind(f);
680     }
681   vars.rebind(formals_);
682   body_->markBoundVars(vars, 1);
683   vars.unbind(formals_);
684 }
685
686 LetExpression::LetExpression(Vector<const Identifier *> &vars,
687                              NCVector<Owner<Expression> > &inits,
688                              Owner<Expression> &body,
689                              const Location &loc)
690 : Expression(loc)
691 {
692   vars.swap(vars_);
693   inits.swap(inits_);
694   body.swap(body_);
695 }
696
697 bool LetExpression::canEval(bool maybeCall) const
698 {
699   if (!body_->canEval(maybeCall))
700     return 0;
701   for (size_t i = 0; i < inits_.size(); i++)
702     if (!inits_[i]->canEval(1))
703       return 0;
704   return 1;
705 }
706
707 InsnPtr LetExpression::compile(Interpreter &interp, const Environment &env,
708                                int stackPos, const InsnPtr &next)
709 {
710   int nVars = vars_.size();
711   Environment bodyEnv(env);
712   BoundVarList boundVars(vars_);
713   body_->markBoundVars(boundVars, 0);
714   bodyEnv.augmentFrame(boundVars, stackPos);
715   return compileInits(interp, env, boundVars, 0, stackPos,
716                       optimizeCompile(body_, interp, bodyEnv,
717                                       stackPos + nVars,
718                                       PopBindingsInsn::make(nVars, next)));
719 }
720
721 InsnPtr LetExpression::compileInits(Interpreter &interp,
722                                     const Environment &env,
723                                     const BoundVarList &initVars,
724                                     size_t initIndex,
725                                     int stackPos,
726                                     const InsnPtr &next)
727 {
728   if (initIndex >= inits_.size())
729     return next;
730   InsnPtr tem = compileInits(interp, env, initVars, initIndex + 1, stackPos + 1, next);
731   if (initVars[initIndex].boxed())
732     tem = new BoxInsn(tem);
733   return optimizeCompile(inits_[initIndex], interp, env, stackPos, tem);
734 }
735
736 void LetExpression::markBoundVars(BoundVarList &vars, bool shared)
737 {
738   for (size_t i = 0; i < inits_.size(); i++)
739     inits_[i]->markBoundVars(vars, shared);
740   vars.rebind(vars_);
741   body_->markBoundVars(vars, shared);
742   vars.unbind(vars_);
743 }
744
745 LetStarExpression::LetStarExpression(Vector<const Identifier *> &vars,
746                                      NCVector<Owner<Expression> > &inits,
747                                      Owner<Expression> &body,
748                                      const Location &loc)
749 : LetExpression(vars, inits, body, loc)
750 {
751 }
752
753 InsnPtr LetStarExpression::compile(Interpreter &interp,
754                                    const Environment &env,
755                                    int stackPos,
756                                    const InsnPtr &next)
757 {
758   int nVars = vars_.size();
759   Environment bodyEnv(env);
760   BoundVarList vars;
761   for (int i = 0; i < nVars; i++) {
762     if (i > 0)
763       inits_[i]->markBoundVars(vars, 0);
764     vars.append(vars_[i], 0);
765   }
766   body_->markBoundVars(vars, 0);
767   bodyEnv.augmentFrame(vars, stackPos);
768   return compileInits(interp, env, vars, 0, stackPos,
769                       optimizeCompile(body_, interp, bodyEnv,
770                                       stackPos + vars_.size(),
771                                       PopBindingsInsn::make(nVars, next)));
772 }
773
774 InsnPtr LetStarExpression::compileInits(Interpreter &interp,
775                                         const Environment &env,
776                                         const BoundVarList &initVars,
777                                         size_t initIndex,
778                                         int stackPos,
779                                         const InsnPtr &next)
780 {
781   if (initIndex >= inits_.size())
782     return next;
783   Environment nextEnv(env);
784   BoundVarList vars;
785   vars.append(initVars[initIndex].ident, initVars[initIndex].flags);
786   nextEnv.augmentFrame(vars, stackPos);
787   InsnPtr tem
788     = compileInits(interp, nextEnv, initVars, initIndex + 1, stackPos + 1, next);
789   if (initVars[initIndex].boxed())
790     tem = new BoxInsn(tem);
791   return optimizeCompile(inits_[initIndex], interp, env, stackPos, tem);
792 }
793
794 LetrecExpression::LetrecExpression(Vector<const Identifier *> &vars,
795                                    NCVector<Owner<Expression> > &inits,
796                                    Owner<Expression> &body,
797                                    const Location &loc)
798 : Expression(loc)
799 {
800   vars.swap(vars_);
801   inits.swap(inits_);
802   body.swap(body_);
803 }
804
805 bool LetrecExpression::canEval(bool maybeCall) const
806 {
807   if (!body_->canEval(maybeCall))
808     return 0;
809   for (size_t i = 0; i < inits_.size(); i++)
810     if (!inits_[i]->canEval(1))
811       return 0;
812   return 1;
813 }
814
815
816 InsnPtr LetrecExpression::compile(Interpreter &interp, const Environment &env,
817                                   int stackPos, const InsnPtr &next)
818 {
819   int nVars = vars_.size();
820
821   BoundVarList vars(vars_, nVars, BoundVar::assignedFlag);
822
823   Environment bodyEnv(env);
824   for (size_t i = 0; i < nVars; i++)
825     inits_[i]->markBoundVars(vars, 0);
826   body_->markBoundVars(vars, 0);
827   bodyEnv.augmentFrame(vars, stackPos);
828   InsnPtr tem = optimizeCompile(body_, interp, bodyEnv, stackPos + nVars,
829                                 PopBindingsInsn::make(nVars, next));
830
831   for (size_t i = 0; i < nVars; i++)
832     vars[i].flags |= BoundVar::uninitFlag;
833
834   for (int i = 0; i < nVars; i++) {
835     if (vars[i].boxed())
836       tem = new SetBoxInsn(nVars, tem);
837     else
838       tem = new SetImmediateInsn(nVars, tem);
839   }
840   tem = compileInits(interp, bodyEnv, 0, stackPos + nVars, tem);
841   for (int i = nVars; i > 0; --i) {
842     if (vars[i - 1].boxed())
843       tem = new BoxInsn(tem);
844     tem = new ConstantInsn(0, tem);
845   }
846   return tem;
847 }
848
849 InsnPtr LetrecExpression::compileInits(Interpreter &interp,
850                                        const Environment &env,
851                                        size_t initIndex,
852                                        int stackPos,
853                                        const InsnPtr &next)
854 {
855   if (initIndex >= inits_.size())
856     return next;
857   return optimizeCompile(inits_[initIndex], interp, env, stackPos,
858                                     compileInits(interp, env, initIndex + 1,
859                                                  stackPos + 1, next));
860 }
861
862 void LetrecExpression::markBoundVars(BoundVarList &vars, bool shared)
863 {
864   vars.rebind(vars_);
865   for (size_t i = 0; i < inits_.size(); i++)
866     inits_[i]->markBoundVars(vars, shared);
867   body_->markBoundVars(vars, shared);
868   vars.unbind(vars_);
869 }
870
871 QuasiquoteExpression::QuasiquoteExpression(NCVector<Owner<Expression> > &members,
872                                            Vector<PackedBoolean> &spliced,
873                                            Type type,
874                                            const Location &loc)
875 : Expression(loc), spliced_(spliced), type_(type)
876 {
877   members.swap(members_);
878 }
879
880 InsnPtr QuasiquoteExpression::compile(Interpreter &interp, const Environment &env,
881                                       int stackPos, const InsnPtr &next)
882 {
883   InsnPtr tem(next);
884   size_t n = members_.size();
885   if (type_ == vectorType) {
886     bool splicy = 0;
887     for (size_t i = 0; i < n; i++) {
888       if (spliced_[i]) {
889         splicy = 1;
890         break;
891       }
892     }
893     if (!splicy) {
894       tem = new VectorInsn(n, tem);
895       for (size_t i = n; i > 0; i--)
896         tem = members_[i - 1]->compile(interp, env, stackPos + (i - 1), tem);
897       return tem;
898     }
899     tem = new ListToVectorInsn(tem);
900   }
901   else if (type_ == improperType)
902     n--;
903   for (size_t i = 0; i < n; i++) {
904     if (spliced_[i])
905       tem = new AppendInsn(location(), tem);
906     else
907       tem = new ConsInsn(tem);
908     tem = members_[i]->compile(interp, env, stackPos + 1, tem);
909   }
910   if (type_ == improperType)
911     tem = members_.back()->compile(interp, env, stackPos, tem);
912   else
913     tem = new ConstantInsn(interp.makeNil(), tem);
914   return tem;
915 }
916
917 void QuasiquoteExpression::markBoundVars(BoundVarList &vars, bool shared)
918 {
919   for (size_t i = 0; i < members_.size(); i++)
920     members_[i]->markBoundVars(vars, shared);
921 }
922
923 bool QuasiquoteExpression::canEval(bool maybeCall) const
924 {
925   for (size_t i = 0; i < members_.size(); i++)
926     if (!members_[i]->canEval(maybeCall))
927       return 0;
928   return 1;
929 }
930
931 void QuasiquoteExpression::optimize(Interpreter &interp, const Environment &env, Owner<Expression> &expr)
932 {
933   for (size_t i = 0; i < members_.size(); i++)
934     members_[i]->optimize(interp, env, members_[i]);
935   if (type_ == vectorType)
936     return;
937   if (members_.size() == 0) {
938     expr = new ResolvedConstantExpression(interp.makeNil(), location());
939     return;
940   }
941   ELObj *tail = members_.back()->constantValue();
942   if (!tail)
943     return;
944   ASSERT(!(spliced_.back() && type_ == improperType));
945   if (type_ != improperType && !spliced_.back()) {
946     tail = interp.makePair(tail, interp.makeNil());
947     interp.makePermanent(tail);
948   }
949   for (size_t i = members_.size() - 1; i-- > 0;) {
950     ELObj *tem = members_[i]->constantValue();
951     // FIXME optimize splice as well
952     if (!tem || spliced_[i]) {
953       members_.resize(i + 2);
954       type_ = improperType;
955       members_[i + 1] = new ResolvedConstantExpression(tail, location());
956       return;
957     }
958     tail = interp.makePair(tem, tail);
959     interp.makePermanent(tail);
960   }
961   expr = new ResolvedConstantExpression(tail, location());
962 }
963
964 SequenceExpression::SequenceExpression(NCVector<Owner<Expression> > &sequence,
965                                        const Location &loc)
966 : Expression(loc)
967 {
968   ASSERT(sequence.size() > 0);
969   sequence.swap(sequence_);
970 }
971
972 InsnPtr
973 SequenceExpression::compile(Interpreter &interp, const Environment &env,
974                             int stackPos, const InsnPtr &next)
975 {
976   // FIXME optimize this
977   InsnPtr result(sequence_.back()->compile(interp, env, stackPos, next));
978   for (size_t i = sequence_.size() - 1; i > 0; i--)
979     result = sequence_[i - 1]->compile(interp, env, stackPos,
980                                        new PopInsn(result));
981   return result;
982 }
983
984 void SequenceExpression::markBoundVars(BoundVarList &vars, bool shared)
985 {
986   for (size_t i = 0; i < sequence_.size(); i++)
987     sequence_[i]->markBoundVars(vars, shared);
988 }
989
990 bool SequenceExpression::canEval(bool maybeCall) const
991 {
992   for (size_t i = 0; i < sequence_.size(); i++)
993     if (!sequence_[i]->canEval(maybeCall))
994       return 0;
995   return 1;
996 }
997
998 void SequenceExpression::optimize(Interpreter &interp, const Environment &env,
999                                   Owner<Expression> &expr)
1000 {
1001   size_t j = 0;
1002   for (size_t i = 0;; i++) {
1003     if (j != i)
1004       sequence_[j].swap(sequence_[i]);
1005     sequence_[j]->optimize(interp, env, sequence_[j]);
1006     if (i == sequence_.size() - 1)
1007       break;
1008     if (!sequence_[j]->constantValue())
1009       j++;  
1010   }
1011   if (j == 0)
1012     sequence_[0].swap(expr);
1013   else
1014     sequence_.resize(j + 1);
1015 }
1016
1017 AssignmentExpression::AssignmentExpression(const Identifier *var,
1018                                            Owner<Expression> &value,
1019                                            const Location &loc)
1020 : Expression(loc), var_(var)
1021 {
1022   value.swap(value_);
1023 }
1024
1025 InsnPtr AssignmentExpression::compile(Interpreter &interp, const Environment &env,
1026                                       int stackPos, const InsnPtr &next)
1027 {
1028   bool isFrame;
1029   int index;
1030   unsigned flags;
1031   if (!env.lookup(var_, isFrame, index, flags)) {
1032     interp.setNextLocation(location());
1033     unsigned part;
1034     Location loc;
1035     if (var_->defined(part, loc))
1036       interp.message(InterpreterMessages::topLevelAssignment,
1037                      StringMessageArg(var_->name()));
1038     else
1039       interp.message(InterpreterMessages::undefinedVariableReference,
1040                      StringMessageArg(var_->name()));
1041     return new ErrorInsn;
1042   }
1043   InsnPtr result;
1044   if (flags & BoundVar::uninitFlag)
1045     result = new CheckInitInsn(var_, location(), next);
1046   else
1047     result = next;
1048   if (isFrame) {
1049     if (BoundVar::flagsBoxed(flags))
1050       result = new StackSetBoxInsn(index - (stackPos + 1), index, location(), result);
1051     else
1052       result = new StackSetInsn(index - (stackPos + 1), index, result);
1053   }
1054   else {
1055     ASSERT(BoundVar::flagsBoxed(flags));
1056     result = new ClosureSetBoxInsn(index, location(), result);
1057   }
1058   return optimizeCompile(value_, interp, env, stackPos, result);
1059 }
1060  
1061 void AssignmentExpression::markBoundVars(BoundVarList &vars, bool shared)
1062 {
1063   vars.mark(var_,
1064             (BoundVar::usedFlag
1065              |BoundVar::assignedFlag
1066              |(shared ? BoundVar::sharedFlag : 0)));
1067   value_->markBoundVars(vars, shared);
1068 }
1069  
1070 bool AssignmentExpression::canEval(bool maybeCall) const
1071 {
1072   return value_->canEval(maybeCall);
1073 }
1074  
1075 WithModeExpression::WithModeExpression(const ProcessingMode *mode, Owner<Expression> &expr,
1076                                        const Location &loc)
1077 : Expression(loc), mode_(mode)
1078 {
1079   expr.swap(expr_);
1080 }
1081
1082 InsnPtr WithModeExpression::compile(Interpreter &interp, const Environment &env, int stackPos,
1083                                     const InsnPtr &next)
1084 {
1085   if (!mode_->defined()) {
1086     interp.setNextLocation(location());
1087     interp.message(InterpreterMessages::undefinedMode, StringMessageArg(mode_->name()));
1088   }
1089   return new PushModeInsn(mode_,
1090                           optimizeCompile(expr_, interp, env, stackPos,
1091                                           new PopModeInsn(next)));
1092 }
1093
1094 void WithModeExpression::markBoundVars(BoundVarList &vars, bool shared)
1095 {
1096   expr_->markBoundVars(vars, shared);
1097 }
1098
1099 bool WithModeExpression::canEval(bool maybeCall) const
1100 {
1101   return expr_->canEval(maybeCall);
1102 }
1103
1104 StyleExpression::StyleExpression(Vector<const Identifier *> &keys,
1105                                  NCVector<Owner<Expression> > &exprs,
1106                                  const Location &loc)
1107 : Expression(loc)
1108 {
1109   keys.swap(keys_);
1110   exprs.swap(exprs_);
1111 }
1112
1113 // Interpret keywords in the following order of preference
1114 // 1. non-inherited characteristics
1115 // 2. DSSSL defined meaning (use: content-map:) etc
1116 // 3. inherited characteristics
1117
1118 InsnPtr StyleExpression::compile(Interpreter &interp, const Environment &env,
1119                                  int stackPos, const InsnPtr &next)
1120 {
1121   Vector<ConstPtr<InheritedC> > ics;
1122   Vector<ConstPtr<InheritedC> > forceIcs;
1123   Vector<const Identifier *> forceKeys(keys_.size()); 
1124   for (size_t i = 0; i < keys_.size(); i++) {
1125     forceKeys[i] = 0; 
1126     if (keys_[i]->name().size() > 6) {
1127       StringC prefix(keys_[i]->name().data(), 6);  
1128       if (prefix == interp.makeStringC("force!")) {
1129         StringC name(keys_[i]->name().data() + 6, keys_[i]->name().size() - 6);
1130         forceKeys[i] = interp.lookup(name);
1131       }
1132     } 
1133   }
1134   bool hasUse = 0;
1135   size_t useIndex;
1136   BoundVarList boundVars;
1137   env.boundVars(boundVars);
1138   for (size_t i = 0; i < keys_.size(); i++) {
1139     Identifier::SyntacticKey sk;
1140     if (forceKeys[i] 
1141         && maybeStyleKeyword(forceKeys[i])
1142         && !forceKeys[i]->inheritedC().isNull()) {
1143       forceIcs.resize(forceIcs.size() + 1);
1144       exprs_[i]->markBoundVars(boundVars, 0);
1145     }
1146     else if (maybeStyleKeyword(keys_[i])
1147         && !(keys_[i]->syntacticKey(sk) && sk == Identifier::keyUse)
1148         && !keys_[i]->inheritedC().isNull()) {
1149       ics.resize(ics.size() + 1);
1150       exprs_[i]->markBoundVars(boundVars, 0);
1151     } 
1152   }
1153   // FIXME optimize case where ics.size() == 0
1154   boundVars.removeUnused();
1155   BoundVarList noVars;
1156   Environment newEnv(noVars, boundVars);
1157   size_t j = 0;
1158   size_t k = 0;
1159   for (size_t i = 0; i < keys_.size(); i++) {
1160     Identifier::SyntacticKey sk;
1161     if (forceKeys[i] 
1162         && maybeStyleKeyword(forceKeys[i])
1163         && !forceKeys[i]->inheritedC().isNull()) {
1164       exprs_[i]->optimize(interp, newEnv, exprs_[i]);
1165       ELObj *val = exprs_[i]->constantValue();
1166       if (val) {
1167         interp.makePermanent(val);
1168         forceIcs[k] = forceKeys[i]->inheritedC()->make(val, exprs_[i]->location(), interp);
1169         if (forceIcs[k].isNull())
1170           forceIcs.resize(forceIcs.size() - 1);
1171         else
1172           k++;
1173       }
1174       else {
1175         forceIcs[k++] = new VarInheritedC(forceKeys[i]->inheritedC(),
1176                           exprs_[i]->compile(interp, newEnv, 0, InsnPtr()),
1177                                      exprs_[i]->location());
1178       }
1179     }    
1180     else if (!maybeStyleKeyword(keys_[i]))
1181       ;
1182     else if (keys_[i]->syntacticKey(sk) && sk == Identifier::keyUse) {
1183       if (!hasUse) {
1184         hasUse = 1;
1185         useIndex = i;
1186       }
1187     }
1188     else if (!keys_[i]->inheritedC().isNull()) {
1189       exprs_[i]->optimize(interp, newEnv, exprs_[i]);
1190       ELObj *val = exprs_[i]->constantValue();
1191       if (val) {
1192         interp.makePermanent(val);
1193         ics[j] = keys_[i]->inheritedC()->make(val, exprs_[i]->location(), interp);
1194         if (ics[j].isNull())
1195           ics.resize(ics.size() - 1);
1196         else
1197           j++;
1198       }
1199       else {
1200         ics[j++] = new VarInheritedC(keys_[i]->inheritedC(),
1201                                      exprs_[i]->compile(interp, newEnv, 0, InsnPtr()),
1202                                      exprs_[i]->location());
1203       }
1204     }
1205     else
1206       unknownStyleKeyword(keys_[i], interp, location());
1207   }
1208   InsnPtr result
1209     = compilePushVars(interp, env, stackPos + hasUse, boundVars, 0,
1210                       new VarStyleInsn(new StyleSpec(forceIcs, ics), 
1211                                        boundVars.size(), hasUse,
1212                                        new MaybeOverrideStyleInsn(next)));
1213   if (!hasUse)
1214     return result;
1215   else {
1216     result = new CheckStyleInsn(location(), result);
1217     return optimizeCompile(exprs_[useIndex], interp, env, stackPos, result);
1218   }
1219 }
1220
1221 void StyleExpression::markBoundVars(BoundVarList &vars, bool shared)
1222 {
1223   for (size_t i = 0; i < exprs_.size(); i++)
1224     exprs_[i]->markBoundVars(vars, 1);
1225 }
1226
1227 bool StyleExpression::canEval(bool maybeCall) const
1228 {
1229   for (size_t i = 0; i < exprs_.size(); i++)
1230     if (!exprs_[i]->canEval(maybeCall))
1231       return 0;
1232   return 1;
1233 }
1234
1235 void StyleExpression::unknownStyleKeyword(const Identifier *ident, Interpreter &interp,
1236                                           const Location &loc) const
1237 {
1238   interp.setNextLocation(loc);
1239   StringC tem(ident->name());
1240   tem += Char(':');
1241   interp.message(InterpreterMessages::invalidStyleKeyword,
1242                  StringMessageArg(tem));
1243 }
1244
1245 bool StyleExpression::maybeStyleKeyword(const Identifier *ident) const
1246 {
1247   return 1;
1248 }
1249
1250 MakeExpression::MakeExpression(const Identifier *foc,
1251                                Vector<const Identifier *> &keys,
1252                                NCVector<Owner<Expression> > &exprs,
1253                                const Location &loc)
1254 : foc_(foc), StyleExpression(keys, exprs, loc)
1255 {
1256 }
1257
1258 InsnPtr MakeExpression::compile(Interpreter &interp, const Environment &env, int stackPos,
1259                                 const InsnPtr &next)
1260 {
1261   FlowObj *flowObj = foc_->flowObj();
1262   if (!flowObj)  {
1263     interp.setNextLocation(location());
1264     interp.message(InterpreterMessages::unknownFlowObjectClass,
1265                    StringMessageArg(foc_->name()));
1266     flowObj = new (interp) SequenceFlowObj;
1267     interp.makePermanent(flowObj);
1268   }
1269   Owner<Expression> *contentMapExpr = 0;
1270   InsnPtr rest(next);
1271   for (size_t i = 0; i < keys_.size(); i++) {
1272     Identifier::SyntacticKey syn;
1273     if (!flowObj->hasNonInheritedC(keys_[i]) && keys_[i]->syntacticKey(syn)) {
1274       if (syn == Identifier::keyLabel)
1275         rest = optimizeCompile(exprs_[i],
1276                                interp,
1277                                env,
1278                                stackPos + 1,
1279                                new LabelSosofoInsn(exprs_[i]->location(), rest));
1280       else if (syn == Identifier::keyContentMap)
1281         contentMapExpr = &exprs_[i];
1282     }
1283   }
1284   flowObj = applyConstNonInheritedCs(flowObj, interp, env);
1285   size_t nContent = exprs_.size() - keys_.size();
1286   CompoundFlowObj *cFlowObj = flowObj->asCompoundFlowObj();
1287   if (!cFlowObj && nContent > 0) {
1288     interp.setNextLocation(location());
1289     interp.message(InterpreterMessages::atomicContent,
1290                    StringMessageArg(foc_->name()));
1291     nContent = 0;
1292   }
1293   rest = compileNonInheritedCs(interp, env, stackPos + 1, rest);
1294   for (size_t i = 0; i < keys_.size(); i++) {
1295     if (flowObj->hasPseudoNonInheritedC(keys_[i])
1296         && !exprs_[i]->constantValue()) {
1297       rest = exprs_[i]->compile(interp, env, stackPos + 1,
1298                                 new SetPseudoNonInheritedCInsn(keys_[i],
1299                                                                exprs_[i]->location(),
1300                                                                rest));
1301     }
1302   }
1303   // FIXME optimize case where there are no non-inherited styles.
1304   rest = StyleExpression::compile(interp, env, stackPos + 1, new SetStyleInsn(rest));
1305   if (nContent == 0 && !contentMapExpr) {
1306     if (cFlowObj)
1307       return new SetDefaultContentInsn(cFlowObj, location(), rest);
1308     else
1309       return new CopyFlowObjInsn(flowObj, rest);
1310   }
1311   rest = new SetContentInsn(cFlowObj, rest);
1312   if (contentMapExpr) {
1313     rest = optimizeCompile(*contentMapExpr, interp, env, stackPos + 1,
1314                            new ContentMapSosofoInsn((*contentMapExpr)->location(), rest));
1315     if (nContent == 0)
1316       return new MakeDefaultContentInsn(location(), rest);
1317   }
1318   // FIXME get rid of CheckSosofoInsn if we can guarantee result is a SosofoObj.
1319   if (nContent == 1)
1320     return optimizeCompile(exprs_.back(), interp, env, stackPos,
1321                            new CheckSosofoInsn(exprs_.back()->location(), rest));
1322   rest = new SosofoAppendInsn(nContent, rest);
1323   for (size_t i = 1; i <= nContent; i++)
1324     rest = optimizeCompile(exprs_[exprs_.size() - i], interp, env, stackPos + nContent - i,
1325                            new CheckSosofoInsn(exprs_[exprs_.size() - i]->location(), rest));
1326   return rest;
1327 }
1328
1329 FlowObj *MakeExpression::applyConstNonInheritedCs(FlowObj *flowObj, Interpreter &interp,
1330                                                   const Environment &env)
1331 {
1332   FlowObj *result = flowObj;
1333   for (size_t i = 0; i < keys_.size(); i++)
1334     if (flowObj->hasNonInheritedC(keys_[i])
1335         || flowObj->hasPseudoNonInheritedC(keys_[i])) {
1336       exprs_[i]->optimize(interp, env, exprs_[i]);
1337       ELObj *val = exprs_[i]->constantValue();
1338       if (val) {
1339         if (result == flowObj) {
1340           result = flowObj->copy(interp);
1341           interp.makePermanent(result);
1342         }
1343         result->setNonInheritedC(keys_[i], val, exprs_[i]->location(), interp);
1344       }
1345     }
1346   return result;
1347 }
1348
1349 // Have a copied flow object on the stack.
1350 // Generate code to set its non-constant, non-inherited characteristics.
1351
1352 InsnPtr MakeExpression::compileNonInheritedCs(Interpreter &interp, const Environment &env,
1353                                               int stackPos, const InsnPtr &next)
1354 {
1355   FlowObj *flowObj = foc_->flowObj();
1356   if (!flowObj)
1357     return next;
1358   bool gotOne = flowObj->isCharacter();
1359   BoundVarList boundVars;
1360   env.boundVars(boundVars);
1361   for (size_t i = 0; i < keys_.size(); i++) {
1362     if (flowObj->hasNonInheritedC(keys_[i]) && !exprs_[i]->constantValue()) {
1363       exprs_[i]->markBoundVars(boundVars, 0);
1364       gotOne = 1;
1365     }
1366   }
1367   if (!gotOne)
1368     return next;
1369   boundVars.removeUnused();
1370   BoundVarList noVars;
1371   Environment newEnv(noVars, boundVars);
1372   InsnPtr code;
1373   for (size_t i = 0; i < keys_.size(); i++)
1374     if (flowObj->hasNonInheritedC(keys_[i]) && !exprs_[i]->constantValue())
1375      code = exprs_[i]->compile(interp, newEnv, 1,
1376                                   new SetNonInheritedCInsn(keys_[i],
1377                                                            exprs_[i]->location(),
1378                                                            code));
1379   InsnPtr rest(new SetNonInheritedCsSosofoInsn(code, boundVars.size(), next));
1380   if (flowObj->isCharacter()) 
1381     rest = new SetImplicitCharInsn(Location(), rest); 
1382   return compilePushVars(interp, env, stackPos, boundVars, 0, rest);
1383 }
1384
1385 void MakeExpression::unknownStyleKeyword(const Identifier *ident, Interpreter &interp,
1386                                           const Location &loc) const
1387 {
1388   FlowObj *flowObj = foc_->flowObj();
1389   if (!flowObj)
1390     return;
1391   Identifier::SyntacticKey key;
1392   if (ident->syntacticKey(key)) {
1393     switch(key) {
1394     case Identifier::keyLabel:
1395     case Identifier::keyContentMap:
1396       return;
1397     default:
1398       break;
1399     }
1400   }
1401   if (flowObj->hasNonInheritedC(ident)
1402       || flowObj->hasPseudoNonInheritedC(ident))
1403     return;
1404   interp.setNextLocation(loc);
1405   StringC tem(ident->name());
1406   tem += Char(':');
1407   interp.message(InterpreterMessages::invalidMakeKeyword,
1408                  StringMessageArg(tem), StringMessageArg(foc_->name()));
1409 }
1410
1411 bool MakeExpression::maybeStyleKeyword(const Identifier *ident) const
1412 {
1413   FlowObj *flowObj = foc_->flowObj();
1414   if (!flowObj)
1415     return 1;
1416   return (!flowObj->hasNonInheritedC(ident)
1417           && !flowObj->hasPseudoNonInheritedC(ident));
1418 }
1419
1420 Environment::Environment()
1421 : closureVars_(0)
1422 {
1423 }
1424
1425 Environment::Environment(const BoundVarList &frameVars,
1426                          const BoundVarList &closureVars)
1427 : closureVars_(&closureVars)
1428 {
1429   FrameVarList *tem = new FrameVarList;
1430   frameVarList_ = tem;
1431   tem->vars = &frameVars;
1432   tem->stackPos = 0;
1433 }
1434
1435 void Environment::boundVars(BoundVarList &result) const
1436 {
1437   if (closureVars_) {
1438     for (size_t i = 0; i < closureVars_->size(); i++)
1439       result.append((*closureVars_)[i].ident,
1440                     (*closureVars_)[i].flags);
1441   }
1442   for (const FrameVarList *f = frameVarList_.pointer();
1443        f;
1444        f = f->next.pointer()) {
1445     for (size_t i = 0; i < f->vars->size(); i++)
1446       result.append((*f->vars)[i].ident, (*f->vars)[i].flags);
1447   }
1448 }
1449
1450 bool Environment::lookup(const Identifier *ident,
1451                          bool &isFrame, int &index, unsigned &flags)
1452      const
1453 {
1454   for (const FrameVarList *p = frameVarList_.pointer();
1455        p;
1456        p = p->next.pointer()) {
1457     for (size_t i = 0; i < p->vars->size(); i++)
1458       if ((*p->vars)[i].ident == ident) {
1459         isFrame = true;
1460         index = i + p->stackPos;
1461         flags = (*p->vars)[i].flags;
1462         return true;
1463       }
1464   }
1465   if (closureVars_) {
1466     for (size_t i = 0; i < closureVars_->size(); i++)
1467       if ((*closureVars_)[i].ident == ident) {
1468         isFrame = false;
1469         index = i;
1470         flags = (*closureVars_)[i].flags;
1471         return true;
1472       }
1473   }
1474   return false;
1475 }
1476
1477 void Environment::augmentFrame(const BoundVarList &vars, int stackPos)
1478 {
1479   FrameVarList *tem = new FrameVarList;
1480   tem->stackPos = stackPos;
1481   tem->vars = &vars;
1482   tem->next = frameVarList_;
1483   frameVarList_ = tem;
1484 }
1485
1486 BoundVarList::BoundVarList(const Vector<const Identifier *> &idents)
1487 : Vector<BoundVar>(idents.size())
1488 {
1489   for (size_t i = 0; i < size(); i++) {
1490     BoundVar &tem = (*this)[i];
1491     tem.ident = idents[i];
1492     tem.reboundCount = 0;
1493     tem.flags = 0;
1494   }
1495 }
1496
1497 BoundVarList::BoundVarList(const Vector<const Identifier *> &idents, size_t n,
1498                            unsigned flags)
1499 : Vector<BoundVar>(n)
1500 {
1501   for (size_t i = 0; i < n; i++) {
1502     BoundVar &tem = (*this)[i];
1503     tem.ident = idents[i];
1504     tem.reboundCount = 0;
1505     tem.flags = (flags & ~BoundVar::usedFlag);
1506   }
1507 }
1508
1509 void BoundVarList::append(const Identifier *id, unsigned flags)
1510 {
1511   resize(size() + 1);
1512   BoundVar &tem = back();
1513   tem.ident = id;
1514   tem.flags = (flags & ~BoundVar::usedFlag);
1515   tem.reboundCount = 0;
1516 }
1517
1518 void BoundVarList::remove(const Vector<const Identifier *> &idents)
1519 {
1520   size_t j = 0;
1521   for (size_t i = 0; i < size(); i++) {
1522     const Identifier *ident = (*this)[i].ident;
1523     for (size_t k = 0;; k++) {
1524       if (k >= idents.size()) {
1525         if (j != i)
1526           (*this)[j] = (*this)[i];
1527         j++;
1528         break;
1529       }
1530       if (idents[k] == ident)
1531         break;                  // skip it
1532     }
1533   }
1534   resize(j);
1535 }
1536
1537 void BoundVarList::removeUnused()
1538 {
1539   size_t j = 0;
1540   for (size_t i = 0; i < size(); i++) {
1541     if ((*this)[i].flags & BoundVar::usedFlag) {
1542       if (j != i)
1543         (*this)[j] = (*this)[i];
1544       j++;
1545     }
1546   }
1547   resize(j);
1548 }
1549
1550 void BoundVarList::mark(const Identifier *ident, unsigned flags)
1551 {
1552   BoundVar *bv = find(ident);
1553   if (bv && !bv->reboundCount)
1554     bv->flags |= flags;
1555 }
1556
1557 void BoundVarList::rebind(const Vector<const Identifier *> &idents)
1558 {
1559   for (size_t i = 0; i < idents.size(); i++) {
1560     BoundVar *bv = find(idents[i]);
1561     if (bv)
1562       bv->reboundCount += 1;
1563   }
1564 }
1565
1566 void BoundVarList::unbind(const Vector<const Identifier *> &idents)
1567 {
1568   for (size_t i = 0; i < idents.size(); i++) {
1569     BoundVar *bv = find(idents[i]);
1570     if (bv)
1571       bv->reboundCount -= 1;
1572   }
1573 }
1574
1575 BoundVar *BoundVarList::find(const Identifier *ident)
1576 {
1577   for (size_t i = 0; i < size(); i++)
1578     if ((*this)[i].ident == ident)
1579       return &(*this)[i];
1580   return 0;
1581 }
1582
1583 #ifdef DSSSL_NAMESPACE
1584 }
1585 #endif