Initial commit
[profile/ivi/openjade.git] / style / MacroFlowObj.cxx
1 // Copyright (c) 1997 James Clark
2 // See the file copying.txt for copying permission.
3
4 #include "stylelib.h"
5 #include "MacroFlowObj.h"
6 #include "VM.h"
7 #include "Insn2.h"
8 #include "Insn.h"
9 #include "Expression.h"
10 #include "Interpreter.h"
11 #include "ProcessContext.h"
12 #include "macros.h"
13
14 #ifdef DSSSL_NAMESPACE
15 namespace DSSSL_NAMESPACE {
16 #endif
17
18 MacroFlowObj::MacroFlowObj(Vector<const Identifier *> &nics,
19                            NCVector<Owner<Expression> > &inits,
20                            const Identifier *contentsId,
21                            Owner<Expression> &body)
22 : def_(new Definition(nics, inits, contentsId, body))
23 {
24   size_t n = def_->nics().size();
25   charicVals_ = new ELObj *[n];
26   for (size_t i = 0; i < n; i++)
27     charicVals_[i] = 0;
28 }
29
30 MacroFlowObj::MacroFlowObj(const MacroFlowObj &obj)
31 : CompoundFlowObj(obj), def_(obj.def_)
32 {
33   size_t n = def_->nics().size();
34   charicVals_ = new ELObj *[n];
35   for (size_t i = 0; i < n; i++)
36     charicVals_[i] = obj.charicVals_[i];
37 }
38
39 MacroFlowObj::~MacroFlowObj()
40 {
41   delete [] charicVals_;
42 }
43
44 FlowObj *MacroFlowObj::copy(Collector &c) const
45 {
46   return new (c) MacroFlowObj(*this);
47 }
48
49 CompoundFlowObj *MacroFlowObj::asCompoundFlowObj()
50 {
51   if (def_->isCompound())
52     return this;
53   else
54     return 0;
55 }
56
57 bool MacroFlowObj::hasNonInheritedC(const Identifier *id) const
58 {
59   const Vector<const Identifier *> &nics = def_->nics();
60   for (size_t i = 0; i < nics.size(); i++)
61     if (nics[i] == id)
62       return 1;
63   return 0;
64 }
65
66 void MacroFlowObj::setNonInheritedC(const Identifier *id, ELObj *obj, const Location &, Interpreter &)
67 {
68   const Vector<const Identifier *> &nics = def_->nics();
69   for (size_t i = 0;; i++) {
70     if (nics[i] == id) {
71       charicVals_[i] = obj;
72       return;
73     }
74   }
75 }
76
77 void MacroFlowObj::traceSubObjects(Collector &c) const
78 {
79   size_t n = def_->nics().size();
80   for (size_t i = 0; i < n; i++)
81     c.trace(charicVals_[i]);
82   CompoundFlowObj::traceSubObjects(c);
83 }
84
85 class EmptyStyleObj : public StyleObj {
86 public:
87   void appendIter(StyleObjIter &) const { }
88 };
89
90 void MacroFlowObj::unpack(VM &vm)
91 {
92   size_t n = def_->nics().size();
93   vm.needStack(n + 1 + def_->isCompound());
94   for (size_t i = 0; i < n; i++)
95     *vm.sp++ = charicVals_[i];
96   if (def_->isCompound()) {
97     ELObj *tem = content();
98     if (!tem)
99       tem = new (*vm.interp) ProcessChildrenSosofoObj(vm.interp->initialProcessingMode());
100     *vm.sp++ = tem;
101   }
102 }
103
104 void MacroFlowObj::processInner(ProcessContext &context)
105 {
106   FOTBuilder &fotb = context.currentFOTBuilder();
107   fotb.startSequence();
108   def_->process(context, this);
109   fotb.endSequence();
110 }
111
112 MacroFlowObj::Definition::Definition(Vector<const Identifier *> &charics,
113                                      NCVector<Owner<Expression> > &charicInits,
114                                      const Identifier *contentsId,
115                                      Owner<Expression> &body)
116 : contentsId_(contentsId)
117 {
118   charics.swap(charics_);
119   charicInits.swap(charicInits_);
120   charicInits_.resize(charics_.size());
121   body.swap(body_);
122 }
123
124 void MacroFlowObj::Definition::process(ProcessContext &context,
125                                        MacroFlowObj *macro)
126 {
127   VM &vm = context.vm();
128   Interpreter &interp = *vm.interp;;
129   if (code_.isNull())
130     compile(interp);
131   StyleStack *saveStyleStack = vm.styleStack;
132   vm.styleStack = &context.currentStyleStack();
133   unsigned saveSpecLevel = vm.specLevel;
134   vm.specLevel = vm.styleStack->level();
135   Vector<size_t> dep;
136   vm.actualDependencies = &dep;
137   ELObj *obj = context.vm().eval(code_.pointer(), 0, macro);
138   vm.styleStack = saveStyleStack;
139   vm.specLevel = saveSpecLevel;
140   if (!interp.isError(obj)) {
141     ELObjDynamicRoot protect(interp, obj);
142     ((SosofoObj *)obj)->process(context);
143   }
144 }
145
146 class UnpackMacroFlowObjInsn : public Insn {
147 public:
148   UnpackMacroFlowObjInsn(InsnPtr next) : next_(next) { }
149   const Insn *execute(VM &vm) const {
150     ((MacroFlowObj *)*--vm.sp)->unpack(vm);
151     return next_.pointer();
152   }
153 private:
154   InsnPtr next_;
155 };
156
157 void MacroFlowObj::Definition::compile(Interpreter &interp)
158 {
159   InsnPtr result;
160   result = new CheckSosofoInsn(body_->location(), result);
161   int nPush = charics_.size() + (contentsId_ != 0);
162   result = PopBindingsInsn::make(nPush, result);
163   BoundVarList frameVars;
164   for (size_t i = 0; i < charics_.size(); i++) {
165     if (i > 0 && charicInits_[i])
166       charicInits_[i]->markBoundVars(frameVars, 0);
167     frameVars.append(charics_[i], 0);
168   }
169   if (contentsId_)
170     frameVars.append(contentsId_, 0);
171   body_->markBoundVars(frameVars, 0);
172   result = Expression::optimizeCompile(body_, interp,
173                                        Environment(frameVars, BoundVarList()),
174                                        nPush, result);
175   for (size_t i = charics_.size(); i > 0; i--) {
176     int stackOffset = int(i) - nPush - 1;
177     if (frameVars[i - 1].boxed())
178       result = new BoxStackInsn(stackOffset, result);
179     InsnPtr ifNull = new SetKeyArgInsn(stackOffset, result);
180     if (charicInits_[i - 1]) {
181       BoundVarList f(frameVars);
182       f.resize(i - 1);
183       ifNull = Expression::optimizeCompile(charicInits_[i - 1], interp,
184                                            Environment(f, BoundVarList()),
185                                            nPush, ifNull);
186     }
187     else
188       ifNull = new ConstantInsn(interp.makeFalse(), ifNull);
189     result = new TestNullInsn(stackOffset, ifNull, result);
190   }
191   code_ = new UnpackMacroFlowObjInsn(result);
192 }
193
194 #ifdef DSSSL_NAMESPACE
195 }
196 #endif