1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
7 #include "Interpreter.h"
8 #include "InterpreterMessages.h"
9 #include "ELObjMessageArg.h"
10 #include "Expression.h"
14 #ifdef DSSSL_NAMESPACE
15 namespace DSSSL_NAMESPACE {
18 Expression::Expression(const Location &loc)
23 void Expression::optimize(Interpreter &, const Environment &, Owner<Expression> &)
27 ELObj *Expression::constantValue() const
32 const Identifier *Expression::keyword() const
37 void Expression::markBoundVars(BoundVarList &, bool)
41 ConstantExpression::ConstantExpression(ELObj *obj, const Location &loc)
42 : Expression(loc), obj_(obj)
47 ConstantExpression::compile(Interpreter &interp, const Environment &env,
48 int stackPos, const InsnPtr &next)
50 return new ConstantInsn(obj_, new ResolveQuantitiesInsn(location(), next));
53 void ConstantExpression::optimize(Interpreter &interp, const Environment &,
54 Owner<Expression> &expr)
56 ELObj *tem = obj_->resolveQuantities(0, interp, location());
58 interp.makePermanent(tem);
59 expr = new ResolvedConstantExpression(tem, location());
63 bool ConstantExpression::canEval(bool) const
68 const Identifier *ConstantExpression::keyword() const
70 const KeywordObj *k = obj_->asKeyword();
72 return k->identifier();
77 ResolvedConstantExpression::ResolvedConstantExpression(ELObj *obj, const Location &loc)
78 : Expression(loc), obj_(obj)
83 ResolvedConstantExpression::compile(Interpreter &interp, const Environment &env,
84 int stackPos, const InsnPtr &next)
86 return new ConstantInsn(obj_, next);
89 ELObj *ResolvedConstantExpression::constantValue() const
94 bool ResolvedConstantExpression::canEval(bool) const
99 CallExpression::CallExpression(Owner<Expression> &op,
100 NCVector<Owner<Expression> > &args,
108 bool CallExpression::canEval(bool) const
110 if (!op_->canEval(1))
112 for (size_t i = 0; i < args_.size(); i++)
113 if (!args_[i]->canEval(1))
118 int CallExpression::nArgs()
123 InsnPtr CallExpression::compile(Interpreter &interp, const Environment &env,
124 int stackPos, const InsnPtr &next)
126 op_->optimize(interp, env, op_);
127 ELObj *value = op_->constantValue();
130 FunctionObj *func = value->asFunction();
132 interp.setNextLocation(location());
133 interp.message(InterpreterMessages::callNonFunction,
134 ELObjMessageArg(value, interp));
135 return new ErrorInsn;
137 if (nArgs() < func->nRequiredArgs()) {
138 interp.setNextLocation(location());
139 interp.message(InterpreterMessages::missingArg);
140 return new ErrorInsn;
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());
150 else if (!func->restArg()) {
151 interp.setNextLocation(location());
152 interp.message(InterpreterMessages::tooManyArgs);
153 args_.resize(func->nRequiredArgs() + func->nOptionalArgs());
158 if (!next.isNull() && next->isReturn(callerArgs) && !interp.debugMode())
159 result = func->makeTailCallInsn(nArgs(), interp, location(), callerArgs);
161 result = func->makeCallInsn(nArgs(), interp, location(), next);
166 if (!next.isNull() && next->isReturn(callerArgs) && !interp.debugMode())
167 result = new TailApplyInsn(callerArgs, n, location());
169 result = new ApplyInsn(n, location(), next);
170 result = op_->compile(interp, env, stackPos + n, result);
172 for (size_t i = args_.size(); i > 0; i--)
173 result = optimizeCompile(args_[i - 1], interp, env,
174 stackPos + i - 1, result);
178 void CallExpression::markBoundVars(BoundVarList &vars, bool shared)
180 op_->markBoundVars(vars, shared);
181 for (size_t i = 0; i < args_.size(); i++)
182 args_[i]->markBoundVars(vars, shared);
185 VariableExpression::VariableExpression(const Identifier *ident,
187 : Expression(loc), ident_(ident), isTop_(0)
191 InsnPtr VariableExpression::compile(Interpreter &interp,
192 const Environment &env,
199 if (env.lookup(ident_, isFrame, index, flags)) {
200 bool boxed = BoundVar::flagsBoxed(flags);
205 && next->isPopBindings(n, tem)
207 && index - stackPos == -1) {
208 if (flags & BoundVar::uninitFlag)
209 tem = new CheckInitInsn(ident_, location(), tem);
210 // This happens with named let.
212 return new UnboxInsn(tem);
216 if (flags & BoundVar::uninitFlag)
217 tem = new CheckInitInsn(ident_, location(), next);
221 tem = new UnboxInsn(tem);
223 return new StackRefInsn(index - stackPos, index, tem);
225 return new ClosureRefInsn(index, tem);
230 if (!ident_->defined(part, loc)) {
231 interp.setNextLocation(location());
232 interp.message(InterpreterMessages::undefinedVariableReference,
233 StringMessageArg(ident_->name()));
234 return new ErrorInsn;
236 ELObj *val = ident_->computeValue(0, interp);
238 return new TopRefInsn(ident_, next);
239 if (interp.isError(val))
240 return new ErrorInsn;
241 return new ConstantInsn(val, next);
244 void VariableExpression::optimize(Interpreter &interp, const Environment &env,
245 Owner<Expression> &expr)
250 if (env.lookup(ident_, isFrame, index, flags))
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);
265 bool VariableExpression::canEval(bool) const
267 return !isTop_ || ident_->evaluated();
270 void VariableExpression::markBoundVars(BoundVarList &vars, bool shared)
272 vars.mark(ident_, BoundVar::usedFlag | (shared ? BoundVar::sharedFlag : 0));
275 IfExpression::IfExpression(Owner<Expression> &test,
276 Owner<Expression> &consequent,
277 Owner<Expression> &alternate,
282 consequent.swap(consequent_);
283 alternate.swap(alternate_);
286 bool IfExpression::canEval(bool maybeCall) const
288 return (test_->canEval(maybeCall)
289 && consequent_->canEval(maybeCall)
290 && alternate_->canEval(maybeCall));
293 void IfExpression::optimize(Interpreter &interp, const Environment &env,
294 Owner<Expression> &expr)
296 test_->optimize(interp, env, test_);
297 ELObj *obj = test_->constantValue();
300 expr = consequent_.extract();
301 expr->optimize(interp, env, expr);
304 expr = alternate_.extract();
305 expr->optimize(interp, env, expr);
310 InsnPtr IfExpression::compile(Interpreter &interp, const Environment &env,
311 int stackPos, const InsnPtr &next)
313 alternate_->optimize(interp, env, alternate_);
314 if (alternate_->constantValue() == interp.makeFalse())
315 return test_->compile(interp, env, stackPos,
316 new AndInsn(optimizeCompile(consequent_,
321 return test_->compile(interp, env, stackPos,
322 new TestInsn(optimizeCompile(consequent_,
325 alternate_->compile(interp, env,
329 void IfExpression::markBoundVars(BoundVarList &vars, bool shared)
331 test_->markBoundVars(vars, shared);
332 consequent_->markBoundVars(vars, shared);
333 alternate_->markBoundVars(vars, shared);
336 OrExpression::OrExpression(Owner<Expression> &test1,
337 Owner<Expression> &test2,
345 bool OrExpression::canEval(bool maybeCall) const
347 return (test1_->canEval(maybeCall)
348 && test2_->canEval(maybeCall));
351 void OrExpression::optimize(Interpreter &interp, const Environment &env,
352 Owner<Expression> &expr)
354 test1_->optimize(interp, env, test1_);
355 ELObj *obj = test1_->constantValue();
358 expr = test1_.extract();
360 expr = test2_.extract();
361 expr->optimize(interp, env, expr);
366 InsnPtr OrExpression::compile(Interpreter &interp, const Environment &env,
367 int stackPos, const InsnPtr &next)
369 return test1_->compile(interp, env, stackPos,
370 new OrInsn(optimizeCompile(test2_, interp, env,
375 void OrExpression::markBoundVars(BoundVarList &vars, bool shared)
377 test1_->markBoundVars(vars, shared);
378 test2_->markBoundVars(vars, shared);
381 CondFailExpression::CondFailExpression(const Location &loc)
386 InsnPtr CondFailExpression::compile(Interpreter &, const Environment &,
387 int, const InsnPtr &)
389 return new CondFailInsn(location());
392 bool CondFailExpression::canEval(bool maybeCall) const
397 CaseExpression::CaseExpression(Owner<Expression> &key,
398 NCVector<Case> &cases,
399 Owner<Expression> &elseClause,
405 elseClause.swap(else_);
408 InsnPtr CaseExpression::compile(Interpreter &interp,
409 const Environment &env, int stackPos,
414 finish = new PopInsn(else_->compile(interp, env, stackPos, next));
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);
422 // FIXME handle unresolved quantities
423 return key_->compile(interp, env, stackPos, finish);
426 void CaseExpression::markBoundVars(BoundVarList &vars, bool shared)
428 key_->markBoundVars(vars, shared);
429 for (size_t i = 0; i < cases_.size(); i++)
430 cases_[i].expr->markBoundVars(vars, shared);
432 else_->markBoundVars(vars, shared);
435 bool CaseExpression::canEval(bool maybeCall) const
437 if (!key_->canEval(maybeCall))
439 if (else_ && !else_->canEval(maybeCall))
441 for (size_t i = 0; i < cases_.size(); i++) {
442 if (!cases_[i].expr->canEval(maybeCall))
444 if (nResolved_[i] == cases_[i].datums.size())
450 void CaseExpression::optimize(Interpreter &interp, const Environment &env,
451 Owner<Expression> &expr)
453 key_->optimize(interp, env, key_);
454 ELObj *k = key_->constantValue();
455 nResolved_.assign(cases_.size(), 0);
457 for (size_t i = 0; i < cases_.size(); i++) {
458 cases_[i].expr->optimize(interp, env, cases_[i].expr);
460 for (size_t j = 0; j < cases_[i].datums.size(); j++) {
461 ELObj *tem = cases_[i].datums[j]->resolveQuantities(0, interp,
464 if (k && ELObj::eqv(*k, *tem)) {
465 expr = cases_[i].expr.extract();
469 cases_[i].datums[j] = cases_[i].datums[nResolved];
470 cases_[i].datums[nResolved++] = tem;
475 nResolved_[i] = nResolved;
478 else_->optimize(interp, env, else_);
479 if (k && !unresolved)
480 expr = else_.extract();
482 else if (k && !unresolved) {
483 interp.setNextLocation(location());
484 interp.message(InterpreterMessages::caseFail, ELObjMessageArg(k, interp));
487 interp.setNextLocation(location());
488 interp.message(InterpreterMessages::caseUnresolvedQuantities);
493 LambdaExpression::LambdaExpression(Vector<const Identifier *> &formals,
494 NCVector<Owner<Expression> > &inits,
498 Owner<Expression> &body,
502 formals.swap(formals_);
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;
512 bool LambdaExpression::canEval(bool maybeCall) const
516 if (!body_->canEval(1))
518 for (size_t i = 0; i < inits_.size(); i++)
519 if (inits_[i] && !inits_[i]->canEval(1))
524 InsnPtr LambdaExpression::compile(Interpreter &interp, const Environment &env,
525 int stackPos, const InsnPtr &next)
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++) {
534 inits_[i]->markBoundVars(formalVars, 0);
535 formalVars.append(formals_[sig_.nRequiredArgs + i], 0);
538 formalVars.append(formals_.back(), 0);
539 ASSERT(formalVars.size() == formals_.size());
540 body_->markBoundVars(formalVars, 0);
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)
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
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());
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;
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);
573 BoundVarList f(formalVars);
574 f.resize(sig_.nRequiredArgs + i + sig_.restArg);
575 set = optimizeCompile(inits_[i], interp,
576 Environment(f, boundVars),
581 set = new ConstantInsn(interp.makeFalse(), set);
582 next = new TestNullInsn(offset, set, next);
585 if (sig_.restArg || sig_.nKeyArgs) {
586 for (int i = sig_.nOptionalArgs + sig_.nKeyArgs - 1;
587 i >= sig_.nOptionalArgs;
589 if (formalVars[sig_.nRequiredArgs + i].boxed())
590 code = new BoxInsn(code);
592 BoundVarList f(formalVars);
593 f.resize(sig_.nRequiredArgs + i + sig_.restArg);
594 code = optimizeCompile(inits_[i], interp,
595 Environment(f, boundVars),
600 code = new ConstantInsn(interp.makeFalse(), code);
603 if (formalVars.back().boxed())
604 code = new BoxInsn(code);
605 code = new ConstantInsn(interp.makeNil(), code);
607 entryPoints[sig_.nOptionalArgs] = code;
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);
614 BoundVarList f(formalVars);
615 f.resize(sig_.nRequiredArgs + i);
617 = optimizeCompile(inits_[i], interp,
618 Environment(f, boundVars),
623 entryPoints[i] = new ConstantInsn(interp.makeFalse(),
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,
636 code = new VarargsInsn(sig_, entryPoints, location());
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));
646 InsnPtr Expression::compilePushVars(Interpreter &interp,
647 const Environment &env,
649 const BoundVarList &vars,
653 if (varIndex >= vars.size())
658 if (!env.lookup(vars[varIndex].ident, isFrame, index, flags))
661 return new FrameRefInsn(index,
662 compilePushVars(interp, env, stackPos + 1, vars,
663 varIndex + 1, next));
665 return new ClosureRefInsn(index,
666 compilePushVars(interp, env, stackPos + 1, vars,
667 varIndex + 1, next));
670 void LambdaExpression::markBoundVars(BoundVarList &vars, bool shared)
672 for (int i = 0; i < sig_.nOptionalArgs + sig_.nKeyArgs; i++)
674 Vector<const Identifier *> f(formals_);
675 f.resize(sig_.nRequiredArgs + i
676 + (sig_.restArg && i >= sig_.nOptionalArgs));
678 inits_[i]->markBoundVars(vars, 1);
681 vars.rebind(formals_);
682 body_->markBoundVars(vars, 1);
683 vars.unbind(formals_);
686 LetExpression::LetExpression(Vector<const Identifier *> &vars,
687 NCVector<Owner<Expression> > &inits,
688 Owner<Expression> &body,
697 bool LetExpression::canEval(bool maybeCall) const
699 if (!body_->canEval(maybeCall))
701 for (size_t i = 0; i < inits_.size(); i++)
702 if (!inits_[i]->canEval(1))
707 InsnPtr LetExpression::compile(Interpreter &interp, const Environment &env,
708 int stackPos, const InsnPtr &next)
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,
718 PopBindingsInsn::make(nVars, next)));
721 InsnPtr LetExpression::compileInits(Interpreter &interp,
722 const Environment &env,
723 const BoundVarList &initVars,
728 if (initIndex >= inits_.size())
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);
736 void LetExpression::markBoundVars(BoundVarList &vars, bool shared)
738 for (size_t i = 0; i < inits_.size(); i++)
739 inits_[i]->markBoundVars(vars, shared);
741 body_->markBoundVars(vars, shared);
745 LetStarExpression::LetStarExpression(Vector<const Identifier *> &vars,
746 NCVector<Owner<Expression> > &inits,
747 Owner<Expression> &body,
749 : LetExpression(vars, inits, body, loc)
753 InsnPtr LetStarExpression::compile(Interpreter &interp,
754 const Environment &env,
758 int nVars = vars_.size();
759 Environment bodyEnv(env);
761 for (int i = 0; i < nVars; i++) {
763 inits_[i]->markBoundVars(vars, 0);
764 vars.append(vars_[i], 0);
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)));
774 InsnPtr LetStarExpression::compileInits(Interpreter &interp,
775 const Environment &env,
776 const BoundVarList &initVars,
781 if (initIndex >= inits_.size())
783 Environment nextEnv(env);
785 vars.append(initVars[initIndex].ident, initVars[initIndex].flags);
786 nextEnv.augmentFrame(vars, stackPos);
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);
794 LetrecExpression::LetrecExpression(Vector<const Identifier *> &vars,
795 NCVector<Owner<Expression> > &inits,
796 Owner<Expression> &body,
805 bool LetrecExpression::canEval(bool maybeCall) const
807 if (!body_->canEval(maybeCall))
809 for (size_t i = 0; i < inits_.size(); i++)
810 if (!inits_[i]->canEval(1))
816 InsnPtr LetrecExpression::compile(Interpreter &interp, const Environment &env,
817 int stackPos, const InsnPtr &next)
819 int nVars = vars_.size();
821 BoundVarList vars(vars_, nVars, BoundVar::assignedFlag);
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));
831 for (size_t i = 0; i < nVars; i++)
832 vars[i].flags |= BoundVar::uninitFlag;
834 for (int i = 0; i < nVars; i++) {
836 tem = new SetBoxInsn(nVars, tem);
838 tem = new SetImmediateInsn(nVars, tem);
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);
849 InsnPtr LetrecExpression::compileInits(Interpreter &interp,
850 const Environment &env,
855 if (initIndex >= inits_.size())
857 return optimizeCompile(inits_[initIndex], interp, env, stackPos,
858 compileInits(interp, env, initIndex + 1,
859 stackPos + 1, next));
862 void LetrecExpression::markBoundVars(BoundVarList &vars, bool shared)
865 for (size_t i = 0; i < inits_.size(); i++)
866 inits_[i]->markBoundVars(vars, shared);
867 body_->markBoundVars(vars, shared);
871 QuasiquoteExpression::QuasiquoteExpression(NCVector<Owner<Expression> > &members,
872 Vector<PackedBoolean> &spliced,
875 : Expression(loc), spliced_(spliced), type_(type)
877 members.swap(members_);
880 InsnPtr QuasiquoteExpression::compile(Interpreter &interp, const Environment &env,
881 int stackPos, const InsnPtr &next)
884 size_t n = members_.size();
885 if (type_ == vectorType) {
887 for (size_t i = 0; i < n; i++) {
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);
899 tem = new ListToVectorInsn(tem);
901 else if (type_ == improperType)
903 for (size_t i = 0; i < n; i++) {
905 tem = new AppendInsn(location(), tem);
907 tem = new ConsInsn(tem);
908 tem = members_[i]->compile(interp, env, stackPos + 1, tem);
910 if (type_ == improperType)
911 tem = members_.back()->compile(interp, env, stackPos, tem);
913 tem = new ConstantInsn(interp.makeNil(), tem);
917 void QuasiquoteExpression::markBoundVars(BoundVarList &vars, bool shared)
919 for (size_t i = 0; i < members_.size(); i++)
920 members_[i]->markBoundVars(vars, shared);
923 bool QuasiquoteExpression::canEval(bool maybeCall) const
925 for (size_t i = 0; i < members_.size(); i++)
926 if (!members_[i]->canEval(maybeCall))
931 void QuasiquoteExpression::optimize(Interpreter &interp, const Environment &env, Owner<Expression> &expr)
933 for (size_t i = 0; i < members_.size(); i++)
934 members_[i]->optimize(interp, env, members_[i]);
935 if (type_ == vectorType)
937 if (members_.size() == 0) {
938 expr = new ResolvedConstantExpression(interp.makeNil(), location());
941 ELObj *tail = members_.back()->constantValue();
944 ASSERT(!(spliced_.back() && type_ == improperType));
945 if (type_ != improperType && !spliced_.back()) {
946 tail = interp.makePair(tail, interp.makeNil());
947 interp.makePermanent(tail);
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());
958 tail = interp.makePair(tem, tail);
959 interp.makePermanent(tail);
961 expr = new ResolvedConstantExpression(tail, location());
964 SequenceExpression::SequenceExpression(NCVector<Owner<Expression> > &sequence,
968 ASSERT(sequence.size() > 0);
969 sequence.swap(sequence_);
973 SequenceExpression::compile(Interpreter &interp, const Environment &env,
974 int stackPos, const InsnPtr &next)
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));
984 void SequenceExpression::markBoundVars(BoundVarList &vars, bool shared)
986 for (size_t i = 0; i < sequence_.size(); i++)
987 sequence_[i]->markBoundVars(vars, shared);
990 bool SequenceExpression::canEval(bool maybeCall) const
992 for (size_t i = 0; i < sequence_.size(); i++)
993 if (!sequence_[i]->canEval(maybeCall))
998 void SequenceExpression::optimize(Interpreter &interp, const Environment &env,
999 Owner<Expression> &expr)
1002 for (size_t i = 0;; i++) {
1004 sequence_[j].swap(sequence_[i]);
1005 sequence_[j]->optimize(interp, env, sequence_[j]);
1006 if (i == sequence_.size() - 1)
1008 if (!sequence_[j]->constantValue())
1012 sequence_[0].swap(expr);
1014 sequence_.resize(j + 1);
1017 AssignmentExpression::AssignmentExpression(const Identifier *var,
1018 Owner<Expression> &value,
1019 const Location &loc)
1020 : Expression(loc), var_(var)
1025 InsnPtr AssignmentExpression::compile(Interpreter &interp, const Environment &env,
1026 int stackPos, const InsnPtr &next)
1031 if (!env.lookup(var_, isFrame, index, flags)) {
1032 interp.setNextLocation(location());
1035 if (var_->defined(part, loc))
1036 interp.message(InterpreterMessages::topLevelAssignment,
1037 StringMessageArg(var_->name()));
1039 interp.message(InterpreterMessages::undefinedVariableReference,
1040 StringMessageArg(var_->name()));
1041 return new ErrorInsn;
1044 if (flags & BoundVar::uninitFlag)
1045 result = new CheckInitInsn(var_, location(), next);
1049 if (BoundVar::flagsBoxed(flags))
1050 result = new StackSetBoxInsn(index - (stackPos + 1), index, location(), result);
1052 result = new StackSetInsn(index - (stackPos + 1), index, result);
1055 ASSERT(BoundVar::flagsBoxed(flags));
1056 result = new ClosureSetBoxInsn(index, location(), result);
1058 return optimizeCompile(value_, interp, env, stackPos, result);
1061 void AssignmentExpression::markBoundVars(BoundVarList &vars, bool shared)
1065 |BoundVar::assignedFlag
1066 |(shared ? BoundVar::sharedFlag : 0)));
1067 value_->markBoundVars(vars, shared);
1070 bool AssignmentExpression::canEval(bool maybeCall) const
1072 return value_->canEval(maybeCall);
1075 WithModeExpression::WithModeExpression(const ProcessingMode *mode, Owner<Expression> &expr,
1076 const Location &loc)
1077 : Expression(loc), mode_(mode)
1082 InsnPtr WithModeExpression::compile(Interpreter &interp, const Environment &env, int stackPos,
1083 const InsnPtr &next)
1085 if (!mode_->defined()) {
1086 interp.setNextLocation(location());
1087 interp.message(InterpreterMessages::undefinedMode, StringMessageArg(mode_->name()));
1089 return new PushModeInsn(mode_,
1090 optimizeCompile(expr_, interp, env, stackPos,
1091 new PopModeInsn(next)));
1094 void WithModeExpression::markBoundVars(BoundVarList &vars, bool shared)
1096 expr_->markBoundVars(vars, shared);
1099 bool WithModeExpression::canEval(bool maybeCall) const
1101 return expr_->canEval(maybeCall);
1104 StyleExpression::StyleExpression(Vector<const Identifier *> &keys,
1105 NCVector<Owner<Expression> > &exprs,
1106 const Location &loc)
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
1118 InsnPtr StyleExpression::compile(Interpreter &interp, const Environment &env,
1119 int stackPos, const InsnPtr &next)
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++) {
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);
1136 BoundVarList boundVars;
1137 env.boundVars(boundVars);
1138 for (size_t i = 0; i < keys_.size(); i++) {
1139 Identifier::SyntacticKey sk;
1141 && maybeStyleKeyword(forceKeys[i])
1142 && !forceKeys[i]->inheritedC().isNull()) {
1143 forceIcs.resize(forceIcs.size() + 1);
1144 exprs_[i]->markBoundVars(boundVars, 0);
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);
1153 // FIXME optimize case where ics.size() == 0
1154 boundVars.removeUnused();
1155 BoundVarList noVars;
1156 Environment newEnv(noVars, boundVars);
1159 for (size_t i = 0; i < keys_.size(); i++) {
1160 Identifier::SyntacticKey sk;
1162 && maybeStyleKeyword(forceKeys[i])
1163 && !forceKeys[i]->inheritedC().isNull()) {
1164 exprs_[i]->optimize(interp, newEnv, exprs_[i]);
1165 ELObj *val = exprs_[i]->constantValue();
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);
1175 forceIcs[k++] = new VarInheritedC(forceKeys[i]->inheritedC(),
1176 exprs_[i]->compile(interp, newEnv, 0, InsnPtr()),
1177 exprs_[i]->location());
1180 else if (!maybeStyleKeyword(keys_[i]))
1182 else if (keys_[i]->syntacticKey(sk) && sk == Identifier::keyUse) {
1188 else if (!keys_[i]->inheritedC().isNull()) {
1189 exprs_[i]->optimize(interp, newEnv, exprs_[i]);
1190 ELObj *val = exprs_[i]->constantValue();
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);
1200 ics[j++] = new VarInheritedC(keys_[i]->inheritedC(),
1201 exprs_[i]->compile(interp, newEnv, 0, InsnPtr()),
1202 exprs_[i]->location());
1206 unknownStyleKeyword(keys_[i], interp, location());
1209 = compilePushVars(interp, env, stackPos + hasUse, boundVars, 0,
1210 new VarStyleInsn(new StyleSpec(forceIcs, ics),
1211 boundVars.size(), hasUse,
1212 new MaybeOverrideStyleInsn(next)));
1216 result = new CheckStyleInsn(location(), result);
1217 return optimizeCompile(exprs_[useIndex], interp, env, stackPos, result);
1221 void StyleExpression::markBoundVars(BoundVarList &vars, bool shared)
1223 for (size_t i = 0; i < exprs_.size(); i++)
1224 exprs_[i]->markBoundVars(vars, 1);
1227 bool StyleExpression::canEval(bool maybeCall) const
1229 for (size_t i = 0; i < exprs_.size(); i++)
1230 if (!exprs_[i]->canEval(maybeCall))
1235 void StyleExpression::unknownStyleKeyword(const Identifier *ident, Interpreter &interp,
1236 const Location &loc) const
1238 interp.setNextLocation(loc);
1239 StringC tem(ident->name());
1241 interp.message(InterpreterMessages::invalidStyleKeyword,
1242 StringMessageArg(tem));
1245 bool StyleExpression::maybeStyleKeyword(const Identifier *ident) const
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)
1258 InsnPtr MakeExpression::compile(Interpreter &interp, const Environment &env, int stackPos,
1259 const InsnPtr &next)
1261 FlowObj *flowObj = foc_->flowObj();
1263 interp.setNextLocation(location());
1264 interp.message(InterpreterMessages::unknownFlowObjectClass,
1265 StringMessageArg(foc_->name()));
1266 flowObj = new (interp) SequenceFlowObj;
1267 interp.makePermanent(flowObj);
1269 Owner<Expression> *contentMapExpr = 0;
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],
1279 new LabelSosofoInsn(exprs_[i]->location(), rest));
1280 else if (syn == Identifier::keyContentMap)
1281 contentMapExpr = &exprs_[i];
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()));
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(),
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) {
1307 return new SetDefaultContentInsn(cFlowObj, location(), rest);
1309 return new CopyFlowObjInsn(flowObj, rest);
1311 rest = new SetContentInsn(cFlowObj, rest);
1312 if (contentMapExpr) {
1313 rest = optimizeCompile(*contentMapExpr, interp, env, stackPos + 1,
1314 new ContentMapSosofoInsn((*contentMapExpr)->location(), rest));
1316 return new MakeDefaultContentInsn(location(), rest);
1318 // FIXME get rid of CheckSosofoInsn if we can guarantee result is a SosofoObj.
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));
1329 FlowObj *MakeExpression::applyConstNonInheritedCs(FlowObj *flowObj, Interpreter &interp,
1330 const Environment &env)
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();
1339 if (result == flowObj) {
1340 result = flowObj->copy(interp);
1341 interp.makePermanent(result);
1343 result->setNonInheritedC(keys_[i], val, exprs_[i]->location(), interp);
1349 // Have a copied flow object on the stack.
1350 // Generate code to set its non-constant, non-inherited characteristics.
1352 InsnPtr MakeExpression::compileNonInheritedCs(Interpreter &interp, const Environment &env,
1353 int stackPos, const InsnPtr &next)
1355 FlowObj *flowObj = foc_->flowObj();
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);
1369 boundVars.removeUnused();
1370 BoundVarList noVars;
1371 Environment newEnv(noVars, boundVars);
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(),
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);
1385 void MakeExpression::unknownStyleKeyword(const Identifier *ident, Interpreter &interp,
1386 const Location &loc) const
1388 FlowObj *flowObj = foc_->flowObj();
1391 Identifier::SyntacticKey key;
1392 if (ident->syntacticKey(key)) {
1394 case Identifier::keyLabel:
1395 case Identifier::keyContentMap:
1401 if (flowObj->hasNonInheritedC(ident)
1402 || flowObj->hasPseudoNonInheritedC(ident))
1404 interp.setNextLocation(loc);
1405 StringC tem(ident->name());
1407 interp.message(InterpreterMessages::invalidMakeKeyword,
1408 StringMessageArg(tem), StringMessageArg(foc_->name()));
1411 bool MakeExpression::maybeStyleKeyword(const Identifier *ident) const
1413 FlowObj *flowObj = foc_->flowObj();
1416 return (!flowObj->hasNonInheritedC(ident)
1417 && !flowObj->hasPseudoNonInheritedC(ident));
1420 Environment::Environment()
1425 Environment::Environment(const BoundVarList &frameVars,
1426 const BoundVarList &closureVars)
1427 : closureVars_(&closureVars)
1429 FrameVarList *tem = new FrameVarList;
1430 frameVarList_ = tem;
1431 tem->vars = &frameVars;
1435 void Environment::boundVars(BoundVarList &result) const
1438 for (size_t i = 0; i < closureVars_->size(); i++)
1439 result.append((*closureVars_)[i].ident,
1440 (*closureVars_)[i].flags);
1442 for (const FrameVarList *f = frameVarList_.pointer();
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);
1450 bool Environment::lookup(const Identifier *ident,
1451 bool &isFrame, int &index, unsigned &flags)
1454 for (const FrameVarList *p = frameVarList_.pointer();
1456 p = p->next.pointer()) {
1457 for (size_t i = 0; i < p->vars->size(); i++)
1458 if ((*p->vars)[i].ident == ident) {
1460 index = i + p->stackPos;
1461 flags = (*p->vars)[i].flags;
1466 for (size_t i = 0; i < closureVars_->size(); i++)
1467 if ((*closureVars_)[i].ident == ident) {
1470 flags = (*closureVars_)[i].flags;
1477 void Environment::augmentFrame(const BoundVarList &vars, int stackPos)
1479 FrameVarList *tem = new FrameVarList;
1480 tem->stackPos = stackPos;
1482 tem->next = frameVarList_;
1483 frameVarList_ = tem;
1486 BoundVarList::BoundVarList(const Vector<const Identifier *> &idents)
1487 : Vector<BoundVar>(idents.size())
1489 for (size_t i = 0; i < size(); i++) {
1490 BoundVar &tem = (*this)[i];
1491 tem.ident = idents[i];
1492 tem.reboundCount = 0;
1497 BoundVarList::BoundVarList(const Vector<const Identifier *> &idents, size_t n,
1499 : Vector<BoundVar>(n)
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);
1509 void BoundVarList::append(const Identifier *id, unsigned flags)
1512 BoundVar &tem = back();
1514 tem.flags = (flags & ~BoundVar::usedFlag);
1515 tem.reboundCount = 0;
1518 void BoundVarList::remove(const Vector<const Identifier *> &idents)
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()) {
1526 (*this)[j] = (*this)[i];
1530 if (idents[k] == ident)
1537 void BoundVarList::removeUnused()
1540 for (size_t i = 0; i < size(); i++) {
1541 if ((*this)[i].flags & BoundVar::usedFlag) {
1543 (*this)[j] = (*this)[i];
1550 void BoundVarList::mark(const Identifier *ident, unsigned flags)
1552 BoundVar *bv = find(ident);
1553 if (bv && !bv->reboundCount)
1557 void BoundVarList::rebind(const Vector<const Identifier *> &idents)
1559 for (size_t i = 0; i < idents.size(); i++) {
1560 BoundVar *bv = find(idents[i]);
1562 bv->reboundCount += 1;
1566 void BoundVarList::unbind(const Vector<const Identifier *> &idents)
1568 for (size_t i = 0; i < idents.size(); i++) {
1569 BoundVar *bv = find(idents[i]);
1571 bv->reboundCount -= 1;
1575 BoundVar *BoundVarList::find(const Identifier *ident)
1577 for (size_t i = 0; i < size(); i++)
1578 if ((*this)[i].ident == ident)
1583 #ifdef DSSSL_NAMESPACE