1 // Copyright (c) 1996 James Clark
2 // See the file copying.txt for copying permission.
3 
4 #ifndef Insn_INCLUDED
5 #define Insn_INCLUDED 1
6 
7 #include "ELObj.h"
8 #include "Resource.h"
9 #include "Ptr.h"
10 #include "Location.h"
11 #include "Message.h"
12 
13 #ifdef DSSSL_NAMESPACE
14 namespace DSSSL_NAMESPACE {
15 #endif
16 
17 class VM;
18 class EvalContext;
19 class Interpreter;
20 
21 class Insn : public Resource {
22 public:
23   virtual ~Insn();
24   virtual const Insn *execute(VM &) const = 0;
25   virtual bool isReturn(int &nArgs) const;
26   virtual bool isPopBindings(int &n, ConstPtr<Insn> &) const;
27 };
28 
29 typedef ConstPtr<Insn> InsnPtr;
30 
31 class ErrorInsn : public Insn {
32 public:
33   const Insn *execute(VM &) const;
34 };
35 
36 class CondFailInsn : public ErrorInsn {
37 public:
38   CondFailInsn(const Location &loc);
39   const Insn *execute(VM &) const;
40 private:
41   Location loc_;
42 };
43 
44 class CaseFailInsn : public ErrorInsn {
45 public:
46   CaseFailInsn(const Location &loc);
47   const Insn *execute(VM &) const;
48 private:
49   Location loc_;
50 };
51 
52 class ConstantInsn : public Insn {
53 public:
54   ConstantInsn(ELObj *, InsnPtr);
55   const Insn *execute(VM &) const;
56 private:
57   ELObj *value_;
58   InsnPtr next_;
59 };
60 
61 class ResolveQuantitiesInsn : public Insn {
62 public:
63   ResolveQuantitiesInsn(const Location &, InsnPtr);
64   const Insn *execute(VM &) const;
65 private:
66   Location loc_;
67   InsnPtr next_;
68 };
69 
70 class TestInsn : public Insn {
71 public:
72   TestInsn(InsnPtr, InsnPtr);
73   const Insn *execute(VM &) const;
74 private:
75   InsnPtr consequent_;
76   InsnPtr alternative_;
77 };
78 
79 class OrInsn : public Insn {
80 public:
81   OrInsn(InsnPtr nextTest, InsnPtr next);
82   const Insn *execute(VM &) const;
83 private:
84   InsnPtr nextTest_;
85   InsnPtr next_;
86 };
87 
88 class AndInsn : public Insn {
89 public:
90   AndInsn(InsnPtr nextTest, InsnPtr next);
91   const Insn *execute(VM &) const;
92 private:
93   InsnPtr nextTest_;
94   InsnPtr next_;
95 };
96 
97 class CaseInsn : public Insn {
98 public:
99   CaseInsn(ELObj *, InsnPtr match, InsnPtr fail);
100   const Insn *execute(VM &) const;
101 private:
102   ELObj *obj_;
103   InsnPtr match_;
104   InsnPtr fail_;
105 };
106 
107 class PopInsn : public Insn {
108 public:
109   PopInsn(InsnPtr next);
110   const Insn *execute(VM &) const;
111 private:
112   InsnPtr next_;
113 };
114 
115 class ConsInsn : public Insn {
116 public:
117   ConsInsn(InsnPtr next);
118   const Insn *execute(VM &) const;
119 private:
120   InsnPtr next_;
121 };
122 
123 class AppendInsn : public Insn {
124 public:
125   AppendInsn(const Location &, InsnPtr next);
126   const Insn *execute(VM &) const;
127 private:
128   Location loc_;
129   InsnPtr next_;
130 };
131 
132 class ApplyBaseInsn : public Insn {
133 public:
134   ApplyBaseInsn(int nArgs, const Location &);
135 protected:
136   FunctionObj *decodeArgs(VM &) const;
137   Location loc_;
138   int nArgs_;
139 };
140 
141 class ApplyInsn : public ApplyBaseInsn {
142 public:
143   ApplyInsn(int nArgs, const Location &, InsnPtr);
144   const Insn *execute(VM &) const;
145 private:
146   InsnPtr next_;
147 };
148 
149 class TailApplyInsn : public ApplyBaseInsn {
150 public:
151   TailApplyInsn(int nCallerArgs, int nArgs, const Location &);
152   const Insn *execute(VM &) const;
153 private:
154   int nCallerArgs_;
155 };
156 
157 class FrameRefInsn : public Insn {
158 public:
159   FrameRefInsn(int index, InsnPtr next);
160   const Insn *execute(VM &vm) const;
161 private:
162   int index_;
163   InsnPtr next_;
164 };
165 
166 class StackRefInsn : public Insn {
167 public:
168   StackRefInsn(int index, int frameIndex, InsnPtr next);
169   const Insn *execute(VM &vm) const;
170 private:
171   int index_;			// always negative
172   int frameIndex_;
173   InsnPtr next_;
174 };
175 
176 class ClosureRefInsn : public Insn {
177 public:
178   ClosureRefInsn(int index, InsnPtr next);
179   const Insn *execute(VM &vm) const;
180 private:
181   int index_;
182   InsnPtr next_;
183 };
184 
185 class StackSetBoxInsn : public Insn {
186 public:
187   StackSetBoxInsn(int index, int frameIndex, const Location &loc, InsnPtr next);
188   const Insn *execute(VM &vm) const;
189 private:
190   int index_;			// always negative
191   int frameIndex_;
192   Location loc_;
193   InsnPtr next_;
194 };
195 
196 class StackSetInsn : public Insn {
197 public:
198   StackSetInsn(int index, int frameIndex, InsnPtr next);
199   const Insn *execute(VM &vm) const;
200 private:
201   int index_;			// always negative
202   int frameIndex_;
203   InsnPtr next_;
204 };
205 
206 class ClosureSetBoxInsn : public Insn {
207 public:
208   ClosureSetBoxInsn(int index, const Location &loc, InsnPtr next);
209   const Insn *execute(VM &vm) const;
210 private:
211   int index_;
212   Location loc_;
213   InsnPtr next_;
214 };
215 
216 class TopRefInsn : public Insn {
217 public:
218   TopRefInsn(const Identifier *var, InsnPtr next);
219   const Insn *execute(VM &vm) const;
220 private:
221   const Identifier *var_;
222   InsnPtr next_;
223   Location loc_;
224 };
225 
226 class PopBindingsInsn : public Insn {
227 public:
228   const Insn *execute(VM &vm) const;
229   bool isPopBindings(int &n, InsnPtr &) const;
230   static InsnPtr make(int n, InsnPtr next);
231 private:
232   PopBindingsInsn(int n, InsnPtr next);
233   int n_;
234   InsnPtr next_;
235 };
236 
237 class PrimitiveObj;
238 
239 class PrimitiveCallInsn : public Insn {
240 public:
241   PrimitiveCallInsn(int nArgs, PrimitiveObj *, const Location &, InsnPtr);
242   const Insn *execute(VM &) const;
243 private:
244   int nArgs_;
245   PrimitiveObj *prim_;
246   Location loc_;
247   InsnPtr next_;
248 };
249 
250 struct Signature {
251   int nRequiredArgs;
252   int nOptionalArgs;
253   bool restArg;
254   int nKeyArgs;
255   const Identifier *const *keys;
256 };
257 
258 // This Insn constructs a ClosureObj.
259 
260 class ClosureInsn : public Insn {
261 public:
262   ClosureInsn(const Signature *, InsnPtr code, int displayLength, InsnPtr next);
263   const Insn *execute(VM &) const;
264 private:
265   const Signature *sig_;
266   InsnPtr code_;
267   int displayLength_;
268   InsnPtr next_;
269 };
270 
271 class ClosureObj;
272 
273 class FunctionCallInsn : public Insn {
274 public:
275   FunctionCallInsn(int nArgs, FunctionObj *, const Location &, InsnPtr);
276   const Insn *execute(VM &) const;
277 private:
278   int nArgs_;
279   FunctionObj *function_;		// must be permanent
280   Location loc_;
281   InsnPtr next_;
282 };
283 
284 class FunctionTailCallInsn : public Insn {
285 public:
286   FunctionTailCallInsn(int nArgs, FunctionObj *, const Location &,
287 		       int nCallerArgs);
288   const Insn *execute(VM &) const;
289 private:
290   int nArgs_;
291   FunctionObj *function_;		// must be permanent
292   Location loc_;
293   int nCallerArgs_;
294 };
295 
296 class VarargsInsn : public Insn {
297 public:
298   VarargsInsn(const Signature &, Vector<InsnPtr> &entryPoints,
299 	      const Location &);
300   const Insn *execute(VM &) const;
301 private:
302   const Signature *sig_;
303   Vector<InsnPtr> entryPoints_;
304   Location loc_;
305 };
306 
307 class SetKeyArgInsn : public Insn {
308 public:
309   SetKeyArgInsn(int offset, InsnPtr);
310   const Insn *execute(VM &) const;
311 private:
312   int offset_;
313   InsnPtr next_;
314 };
315 
316 class TestNullInsn : public Insn {
317 public:
318   TestNullInsn(int offset, InsnPtr ifNull, InsnPtr ifNotNull);
319   const Insn *execute(VM &) const;
320 private:
321   int offset_;
322   InsnPtr ifNull_;
323   InsnPtr ifNotNull_;
324   InsnPtr next_;
325 };
326 
327 class ReturnInsn : public Insn {
328 public:
329   ReturnInsn(int totalArgs);
330   const Insn *execute(VM &) const;
331   bool isReturn(int &nArgs) const;
332 private:
333   int totalArgs_;
334 };
335 
336 class FunctionObj : public ELObj {
337 public:
FunctionObj(const Signature * sig)338   FunctionObj(const Signature *sig) : sig_(sig) { }
339   int totalArgs();
340   int nRequiredArgs();
341   int nOptionalArgs();
342   int nKeyArgs();
343   bool restArg();
344   virtual const Insn *call(VM &vm, const Location &, const Insn *next) = 0;
345   virtual const Insn *tailCall(VM &vm, const Location &, int nCallerArgs) = 0;
346   virtual InsnPtr makeCallInsn(int nArgs, Interpreter &, const Location &,
347 			       InsnPtr next);
348   virtual InsnPtr makeTailCallInsn(int nArgs, Interpreter &,
349 				   const Location &, int nCallerArgs);
signature()350   const Signature &signature() const { return *sig_; }
351   FunctionObj *asFunction();
352   virtual void setArgToCC(VM &);
353 private:
354   const Signature *sig_;
355 };
356 
357 class PrimitiveObj : public FunctionObj {
358 public:
PrimitiveObj(const Signature * sig)359   PrimitiveObj(const Signature *sig) : FunctionObj(sig) { }
360   const Insn *call(VM &vm, const Location &, const Insn *next);
361   const Insn *tailCall(VM &vm, const Location &, int nCallerArgs);
362   InsnPtr makeCallInsn(int nArgs, Interpreter &, const Location &, InsnPtr next);
363   virtual ELObj *primitiveCall(int nArgs, ELObj **args, EvalContext &, Interpreter &,
364 			       const Location &) = 0;
365   void setIdentifier(const Identifier *ident);
366 protected:
367   ELObj *argError(Interpreter &, const Location &,
368 		  const MessageType3 &, unsigned, ELObj *) const;
369   ELObj *noCurrentNodeError(Interpreter &, const Location &) const;
370 private:
371   const Identifier *ident_;
372 };
373 
374 class ApplyPrimitiveObj : public FunctionObj {
375 public:
376   ApplyPrimitiveObj();
377   const Insn *call(VM &vm, const Location &, const Insn *next);
378   const Insn *tailCall(VM &vm, const Location &, int nCallerArgs);
379 private:
380   bool shuffle(VM &vm, const Location &loc);
381   static const Signature signature_;
382 };
383 
384 class CallWithCurrentContinuationPrimitiveObj : public FunctionObj {
385 public:
386   CallWithCurrentContinuationPrimitiveObj();
387   const Insn *call(VM &vm, const Location &, const Insn *next);
388   const Insn *tailCall(VM &vm, const Location &, int nCallerArgs);
389 private:
390   static const Signature signature_;
391 };
392 
393 class ClosureObj : public FunctionObj {
394 public:
new(size_t,Collector & c)395   void *operator new(size_t, Collector &c) {
396     return c.allocateObject(1);
397   }
398   ClosureObj(const Signature *, InsnPtr, ELObj **display);
~ClosureObj()399   ~ClosureObj() { delete [] display_; }
400   ELObj **display();
401   const Insn *call(VM &, const Location &, const Insn *);
402   const Insn *tailCall(VM &, const Location &, int nCallerArgs);
403   void traceSubObjects(Collector &) const;
404   ELObj *display(int) const;
405   void setArgToCC(VM &);
406 private:
407   InsnPtr code_;
408   // terminated by null pointer.
409   // null if empty.
410   ELObj **display_;
411 };
412 
413 class ContinuationObj : public FunctionObj {
414 public:
415   ContinuationObj();
416   const Insn *call(VM &, const Location &, const Insn *);
417   const Insn *tailCall(VM &, const Location &, int nCallerArgs);
set(size_t stackSize,size_t controlStackSize)418   void set(size_t stackSize, size_t controlStackSize) {
419     stackSize_ = stackSize;
420     controlStackSize_ = controlStackSize;
421   }
kill()422   void kill() { controlStackSize_ = 0; }
live()423   bool live() const { return controlStackSize_ > 0; }
424 private:
425   size_t stackSize_;
426   size_t controlStackSize_;
427   static const Signature signature_;
428 };
429 
430 class BoxObj : public ELObj {
431 public:
432   BoxObj();
433   BoxObj(ELObj *);
434   BoxObj *asBox();
435   void traceSubObjects(Collector &) const;
436   ELObj *value;
437 };
438 
439 class SetBoxInsn : public Insn {
440 public:
441   SetBoxInsn(int n, InsnPtr next);
442   const Insn *execute(VM &vm) const;
443 private:
444   int n_;
445   InsnPtr next_;
446 };
447 
448 class SetImmediateInsn : public Insn {
449 public:
450   SetImmediateInsn(int n, InsnPtr next);
451   const Insn *execute(VM &vm) const;
452 private:
453   int n_;
454   InsnPtr next_;
455 };
456 
457 class UnboxInsn : public Insn {
458 public:
459   UnboxInsn(InsnPtr next);
460   const Insn *execute(VM &vm) const;
461 private:
462   InsnPtr next_;
463 };
464 
465 class CheckInitInsn : public Insn {
466 public:
467   CheckInitInsn(const Identifier *ident, const Location &, InsnPtr next);
468   const Insn *execute(VM &vm) const;
469 private:
470   const Identifier *ident_;
471   Location loc_;
472   InsnPtr next_;
473 };
474 
475 class BoxInsn : public Insn {
476 public:
477   BoxInsn(InsnPtr next);
478   const Insn *execute(VM &vm) const;
479 private:
480   InsnPtr next_;
481 };
482 
483 class BoxArgInsn : public Insn {
484 public:
485   BoxArgInsn(int n, InsnPtr next);
486   const Insn *execute(VM &vm) const;
487 private:
488   int n_;
489   InsnPtr next_;
490 };
491 
492 class BoxStackInsn : public Insn {
493 public:
494   BoxStackInsn(int n, InsnPtr next);
495   const Insn *execute(VM &vm) const;
496 private:
497   int n_;
498   InsnPtr next_;
499 };
500 
501 class VectorInsn : public Insn {
502 public:
503   VectorInsn(size_t n, InsnPtr next);
504   const Insn *execute(VM &vm) const;
505 private:
506   size_t n_;
507   InsnPtr next_;
508 };
509 
510 class ListToVectorInsn : public Insn {
511 public:
512   ListToVectorInsn(InsnPtr next);
513   const Insn *execute(VM &vm) const;
514 private:
515   InsnPtr next_;
516 };
517 
518 inline
nRequiredArgs()519 int FunctionObj::nRequiredArgs()
520 {
521   return signature().nRequiredArgs;
522 }
523 
524 inline
nOptionalArgs()525 int FunctionObj::nOptionalArgs()
526 {
527   return signature().nOptionalArgs;
528 }
529 
530 inline
restArg()531 bool FunctionObj::restArg()
532 {
533   return signature().restArg;
534 }
535 
536 inline
nKeyArgs()537 int FunctionObj::nKeyArgs()
538 {
539   return signature().nKeyArgs;
540 }
541 
542 inline
totalArgs()543 int FunctionObj::totalArgs()
544 {
545   const Signature &sig = signature();
546   return sig.nRequiredArgs + sig.nOptionalArgs + sig.nKeyArgs + sig.restArg;
547 }
548 
549 inline
setIdentifier(const Identifier * ident)550 void PrimitiveObj::setIdentifier(const Identifier *ident)
551 {
552   ident_ = ident;
553 }
554 
555 inline
display(int i)556 ELObj *ClosureObj::display(int i) const
557 {
558   return display_[i];
559 }
560 
561 #ifdef DSSSL_NAMESPACE
562 }
563 #endif
564 
565 #endif /* not Insn_INCLUDED */
566