root/trunk/minid/types.d

Revision 420, 19.5 kB (checked in by JarrettBillingsley, 4 weeks ago)

We have class-based OO, once again.

Line 
1 /******************************************************************************
2 License:
3 Copyright (c) 2008 Jarrett Billingsley
4
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the
7 use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it freely,
11 subject to the following restrictions:
12
13     1. The origin of this software must not be misrepresented; you must not
14     claim that you wrote the original software. If you use this software in a
15     product, an acknowledgment in the product documentation would be
16     appreciated but is not required.
17
18     2. Altered source versions must be plainly marked as such, and must not
19     be misrepresented as being the original software.
20
21     3. This notice may not be removed or altered from any source distribution.
22 ******************************************************************************/
23
24 module minid.types;
25
26 version(MDRestrictedCoro) {} else
27     import tango.core.Thread;
28
29 import tango.text.convert.Layout;
30
31 import minid.alloc;
32 import minid.hash;
33 import minid.opcodes;
34 import minid.utils;
35
36 import tango.text.convert.Format;
37
38 // ================================================================================================================================================
39 // Public
40 // ================================================================================================================================================
41
42 /**
43 The native signed integer type on this platform.  This is the same as ptrdiff_t but with a better name.
44 */
45 public alias ptrdiff_t word;
46
47 /**
48 The native unsigned integer type on this platform.  This is the same as size_t but with a better name.
49 */
50 public alias size_t uword;
51
52 /**
53 The underlying D type used to store the MiniD 'int' type.  Defaults to 'long' (64-bit signed integer).  If you
54 change it, you will end up with a functional but nonstandard implementation.
55 */
56 public alias long mdint;
57
58 static assert((cast(mdint)-1) < (cast(mdint)0), "mdint must be signed");
59
60 /**
61 The underlying D type used to store the MiniD 'float' type.  Defaults to 'double'.  If you change it, you will end
62 up with a functional but nonstandard implementation.
63 */
64 public alias double mdfloat;
65
66 /**
67 The current version of MiniD.
68 */
69 public const uint MiniDVersion = MakeVersion!(2, 0);
70
71 /**
72 An alias for the type signature of a native function.  It is defined as uword function(MDThread*, uword).
73 */
74 public alias uword function(MDThread*, uword) NativeFunc;
75
76 /**
77 The MiniD exception type.  This is the type that is thrown whenever you throw an exception from within
78 MiniD, or when you use the throwException API call.  You can't directly instantiate this class, though,
79 since it would be bad if you did (the interpreter needs to keep track of some internal state, which
80 throwException does).  See throwException and catchException in minid.interpreter for more info
81 on MiniD exception handling.
82 */
83 class MDException : Exception
84 {
85     package this(char[] msg)
86     {
87         super(msg);
88     }
89 }
90
91 /**
92 This is a semi-internal exception type.  Normally you won't need to know about it or catch it.  This is
93 thrown when a coroutine (thread) needs to be halted.  It should never propagate out of the coroutine.
94 The only time you might encounter it is if, in the middle of a native MiniD function, one of these
95 is thrown, you might be able to catch it and clean up some resources, but you should rethrow it.
96
97 Like the other exception types, you can't instantiate this directly, but you can halt threads with the
98 "haltThread" function in minid.interpreter.
99 */
100 final class MDHaltException : Exception
101 {
102     package this()
103     {
104         super("MiniD interpreter halted");
105     }
106 }
107
108 /**
109 A string constant indicating the level of coroutine support compiled in.  Is one of "Restricted",
110 "Normal", or "Extended".
111 */
112 version(MDRestrictedCoro)
113 {
114     version(MDExtendedCoro)
115     {
116         pragma(msg, "The 'MDRestrictedCoro' and 'MDExtendedCoro' versions are mutually exclusive.");
117         pragma(msg, "Please define one or the other (or neither), not both.\n");
118         static assert(false, "FAILCOPTER.");
119     }
120
121     const char[] MDCoroSupport = "Restricted";
122 }
123 else version(MDExtendedCoro)
124     const char[] MDCoroSupport = "Extended";
125 else
126     const char[] MDCoroSupport = "Normal";
127
128 // ================================================================================================================================================
129 // Package
130 // ================================================================================================================================================
131
132 align(1) struct MDValue
133 {
134     enum Type : uint
135     {
136         // Value Types
137         Null, // 0
138         Bool,
139         Int,
140         Float,
141         Char,
142
143         // Reference Types
144         String, // 5
145         Table,
146         Array,
147         Function,
148         Class,
149         Instance, // 10
150         Namespace,
151         Thread,
152         NativeObj,
153         WeakRef,
154
155         // Internal types
156         Upvalue, // 15
157         FuncDef,
158         ArrayData
159     }
160
161     package static char[] typeString(MDValue.Type t)
162     {
163         switch(t)
164         {
165             case Type.Null:      return "null";
166             case Type.Bool:      return "bool";
167             case Type.Int:       return "int";
168             case Type.Float:     return "float";
169             case Type.Char:      return "char";
170
171             case Type.String:    return "string";
172             case Type.Table:     return "table";
173             case Type.Array:     return "array";
174             case Type.Function:  return "function";
175             case Type.Class:     return "class";
176             case Type.Instance:  return "instance";
177             case Type.Namespace: return "namespace";
178             case Type.Thread:    return "thread";
179             case Type.NativeObj: return "nativeobj";
180             case Type.WeakRef:   return "weakref";
181
182             case Type.Upvalue:   return "upvalue";
183             case Type.FuncDef:   return "funcdef";
184             case Type.ArrayData: return "arraydata";
185
186             default: assert(false);
187         }
188     }
189
190     package static MDValue nullValue = { type : Type.Null, mInt : 0 };
191
192     package Type type = Type.Null;
193
194     union
195     {
196         package bool mBool;
197         package mdint mInt;
198         package mdfloat mFloat;
199         package dchar mChar;
200
201         package MDBaseObject* mBaseObj;
202         package MDString* mString;
203         package MDTable* mTable;
204         package MDArray* mArray;
205         package MDFunction* mFunction;
206         package MDClass* mClass;
207         package MDInstance* mInstance;
208         package MDNamespace* mNamespace;
209         package MDThread* mThread;
210         package MDNativeObj* mNativeObj;
211         package MDWeakRef* mWeakRef;
212     }
213
214     package static MDValue opCall(T)(T t)
215     {
216         MDValue ret = void;
217         ret = t;
218         return ret;
219     }
220
221     /*
222     Returns true if this and the other value are exactly the same type and the same value.  The semantics
223     of this are exactly the same as the 'is' expression in MiniD.
224     */
225     package int opEquals(ref MDValue other)
226     {
227         if(this.type != other.type)
228             return false;
229
230         switch(this.type)
231         {
232             case Type.Null: return true;
233             case Type.Bool: return this.mBool == other.mBool;
234             case Type.Int: return this.mInt == other.mInt;
235             case Type.Float: return this.mFloat == other.mFloat;
236             case Type.Char: return this.mChar == other.mChar;
237             default: return (this.mBaseObj is other.mBaseObj);
238         }
239     }
240
241     package bool isFalse()
242     {
243         return (type == Type.Null) || (type == Type.Bool && mBool == false) ||
244             (type == Type.Int && mInt == 0) || (type == Type.Float && mFloat == 0.0) || (type == Type.Char && mChar != 0);
245     }
246    
247     package void opAssign(bool src)
248     {
249         type = Type.Bool;
250         mBool = src;
251     }
252    
253     package void opAssign(mdint src)
254     {
255         type = Type.Int;
256         mInt = src;
257     }
258    
259     package void opAssign(mdfloat src)
260     {
261         type = Type.Float;
262         mFloat = src;
263     }
264    
265     package void opAssign(dchar src)
266     {
267         type = Type.Char;
268         mChar = src;
269     }
270    
271     package void opAssign(MDString* src)
272     {
273         type = Type.String;
274         mString = src;
275     }
276    
277     package void opAssign(MDTable* src)
278     {
279         type = Type.Table;
280         mTable = src;
281     }
282    
283     package void opAssign(MDArray* src)
284     {
285         type = Type.Array;
286         mArray = src;
287     }
288
289     package void opAssign(MDFunction* src)
290     {
291         type = Type.Function;
292         mFunction = src;
293     }
294    
295     package void opAssign(MDClass* src)
296     {
297         type = Type.Class;
298         mClass = src;
299     }
300    
301     package void opAssign(MDInstance* src)
302     {
303         type = Type.Instance;
304         mInstance = src;
305     }
306
307     package void opAssign(MDNamespace* src)
308     {
309         type = Type.Namespace;
310         mNamespace = src;
311     }
312
313     package void opAssign(MDThread* src)
314     {
315         type = Type.Thread;
316         mThread = src;
317     }
318    
319     package void opAssign(MDNativeObj* src)
320     {
321         type = Type.NativeObj;
322         mNativeObj = src;
323     }
324    
325     package void opAssign(MDWeakRef* src)
326     {
327         type = Type.WeakRef;
328         mWeakRef = src;
329     }
330
331     package void opAssign(MDBaseObject* src)
332     {
333         type = src.mType;
334         mBaseObj = src;
335     }
336
337     package bool isObject()
338     {
339         return type >= Type.String;
340     }
341
342     package GCObject* toGCObject()
343     {
344         assert(isObject());
345         return cast(GCObject*)mBaseObj;
346     }
347
348     char[] toString()
349     {
350         switch(type)
351         {
352             case Type.Null:      return "null";
353             case Type.Bool:      return Format("{}", mBool);
354             case Type.Int:       return Format("{}", mInt);
355             case Type.Float:     return Format("{}", mFloat);
356             case Type.Char:      return Format("'{}'", mChar);
357             case Type.String:    return Format("\"{}\"", mString.toString());
358             case Type.Table:     return Format("table {:X8}", cast(void*)mTable);
359             case Type.Array:     return Format("array {:X8}", cast(void*)mArray);
360             case Type.Function:  return Format("function {:X8}", cast(void*)mFunction);
361             case Type.Class:     return Format("class {:X8}", cast(void*)mClass);
362             case Type.Instance:  return Format("instance {:X8}", cast(void*)mInstance);
363             case Type.Namespace: return Format("namespace {:X8}", cast(void*)mNamespace);
364             case Type.Thread:    return Format("thread {:X8}", cast(void*)mThread);
365             case Type.NativeObj: return Format("nativeobj {:X8}", cast(void*)mNativeObj);
366             case Type.WeakRef:   return Format("weakref {:X8}", cast(void*)mWeakRef);
367             default: assert(false);
368         }
369     }
370
371     hash_t toHash()
372     {
373         switch(type)
374         {
375             case Type.Null:   return 0;
376             case Type.Bool:   return typeid(typeof(mBool)).getHash(&mBool);
377             case Type.Int:    return typeid(typeof(mInt)).getHash(&mInt);
378             case Type.Float:  return typeid(typeof(mFloat)).getHash(&mFloat);
379             case Type.Char:   return typeid(typeof(mChar)).getHash(&mChar);
380             case Type.String: return mString.hash;
381             default:          return cast(hash_t)cast(void*)mBaseObj;
382         }
383     }
384 }
385
386 template MDObjectMixin(uint type)
387 {
388     mixin GCMixin;
389     package MDValue.Type mType = cast(MDValue.Type)type;
390 }
391
392 struct MDBaseObject
393 {
394     mixin MDObjectMixin!(MDValue.Type.Null);
395 }
396
397 struct MDString
398 {
399     mixin MDObjectMixin!(MDValue.Type.String);
400     package uword hash;
401     package uword length;
402     package uword cpLength;
403
404     package char[] toString()
405     {
406         return (cast(char*)(this + 1))[0 .. this.length];
407     }
408    
409     package uint toHash()
410     {
411         return hash;
412     }
413 }
414
415 struct MDTable
416 {
417     mixin MDObjectMixin!(MDValue.Type.Table);
418     package Hash!(MDValue, MDValue) data;
419 }
420
421 struct MDArrayData
422 {
423     mixin MDObjectMixin!(MDValue.Type.ArrayData);
424     package uword length;
425
426     package MDValue[] toArray()
427     {
428         return (cast(MDValue*)(this + 1))[0 .. length];
429     }
430 }
431
432 struct MDArray
433 {
434     mixin MDObjectMixin!(MDValue.Type.Array);
435     package MDArrayData* data;
436     package MDValue[] slice;
437     package bool isSlice;
438 }
439
440 struct MDFunction
441 {
442     mixin MDObjectMixin!(MDValue.Type.Function);
443     package bool isNative;
444     package MDNamespace* environment;
445     package MDString* name;
446     package uword numUpvals;
447     package MDTable* attrs;
448
449     union
450     {
451         package MDFuncDef* scriptFunc;
452         package NativeFunc nativeFunc;
453     }
454
455     package MDValue[] nativeUpvals()
456     {
457         return (cast(MDValue*)(this + 1))[0 .. numUpvals];
458     }
459
460     package MDUpval*[] scriptUpvals()
461     {
462         return (cast(MDUpval**)(this + 1))[0 .. numUpvals];
463     }
464
465     static assert((MDFuncDef*).sizeof == NativeFunc.sizeof);
466 }
467
468 struct MDClass
469 {
470     mixin MDObjectMixin!(MDValue.Type.Class);
471     package MDString* name;
472     package MDClass* parent;
473     package MDNamespace* fields;
474     package MDTable* attrs;
475     package MDFunction* allocator;
476     package MDFunction* finalizer;
477 }
478
479 struct MDInstance
480 {
481     mixin MDObjectMixin!(MDValue.Type.Instance);
482     package MDClass* parent;
483     package MDNamespace* fields;
484     package MDFunction* finalizer;
485     package uword numValues;
486     package uword extraBytes;
487    
488     package MDValue[] extraValues()
489     {
490         return (cast(MDValue*)(this + 1))[0 .. numValues];
491     }
492    
493     package void[] extraData()
494     {
495         return ((cast(void*)(this + 1)) + (numValues * MDValue.sizeof))[0 .. extraBytes];
496     }
497 }
498
499 struct MDNamespace
500 {
501     mixin MDObjectMixin!(MDValue.Type.Namespace);
502     package Hash!(MDString*, MDValue) data;
503     package MDNamespace* parent;
504     package MDString* name;
505     package MDTable* attrs;
506 }
507
508 package alias uword AbsStack;
509 package alias uword RelStack;
510
511 struct ActRecord
512 {
513     package AbsStack base;
514     package AbsStack savedTop;
515     package AbsStack vargBase;
516     package AbsStack returnSlot;
517     package MDFunction* func;
518     package Instruction* pc;
519     package word numReturns;
520     package MDClass* proto;
521     package uword numTailcalls;
522     package uword firstResult;
523     package uword numResults;
524 }
525
526 struct TryRecord
527 {
528     package bool isCatch;
529     package RelStack catchVarSlot;
530     package uword actRecord;
531     package Instruction* pc;
532 }
533
534 struct MDThread
535 {
536     mixin MDObjectMixin!(MDValue.Type.Thread);
537
538     public enum State
539     {
540         Initial,
541         Waiting,
542         Running,
543         Suspended,
544         Dead
545     }
546
547     static char[][5] StateStrings =
548     [
549         State.Initial: "initial",
550         State.Waiting: "waiting",
551         State.Running: "running",
552         State.Suspended: "suspended",
553         State.Dead: "dead"
554     ];
555
556     package TryRecord[] tryRecs;
557     package TryRecord* currentTR;
558     package uword trIndex = 0;
559
560     package ActRecord[] actRecs;
561     package ActRecord* currentAR;
562     package uword arIndex = 0;
563
564     package MDValue[] stack;
565     package AbsStack stackIndex;
566     package AbsStack stackBase;
567
568     package MDValue[] results;
569     package uword resultIndex = 0;
570
571     package MDUpval* upvalHead;
572    
573     package MDVM* vm;
574     package bool shouldHalt = false;
575
576     package MDFunction* coroFunc;
577     package State state = State.Initial;
578     package uword numYields;
579
580     version(MDExtendedCoro) {} else
581     {
582         package uword savedCallDepth;
583         package uword nativeCallDepth = 0;
584     }
585
586     version(MDRestrictedCoro) {} else
587     {
588         // References a Fiber object
589         package MDNativeObj* coroFiber;
590
591         package Fiber getFiber()
592         {
593             assert(coroFiber !is null);
594             return cast(Fiber)cast(void*)coroFiber.obj;
595         }
596     }
597 }
598
599 struct MDNativeObj
600 {
601     mixin MDObjectMixin!(MDValue.Type.NativeObj);
602     package Object obj;
603 }
604
605 struct MDWeakRef
606 {
607     mixin MDObjectMixin!(MDValue.Type.WeakRef);
608     package MDBaseObject* obj;
609 }
610
611 struct Location
612 {
613     enum Type
614     {
615         Unknown = -2,
616         Native = -1,
617         Script = 0 
618     }
619
620     public MDString* file;
621     // yes, these are 32 bits
622     package int line = 1;
623     package int col = 1;
624
625     public static Location opCall(MDString* file, int line = 1, int col = 1)
626     {
627         Location l = void;
628         l.file = file;
629         l.line = line;
630         l.col = col;
631         return l;
632     }
633 }
634
635 struct MDUpval
636 {
637     mixin MDObjectMixin!(MDValue.Type.Upvalue);
638
639     package MDValue* value;
640     package MDValue closedValue;
641     package MDUpval* nextuv;
642 }
643
644 // The integral members of this struct are fixed at 32 bits for possible cross-platform serialization.
645 struct MDFuncDef
646 {
647     mixin MDObjectMixin!(MDValue.Type.FuncDef);
648
649     package Location location;
650     package bool isVararg;
651     package MDString* name;
652     package uint numParams;
653     package ushort[] paramMasks;
654     package uint numUpvals;
655     package uint stackSize;
656     package MDFuncDef*[] innerFuncs;
657     package MDValue[] constants;
658     package Instruction[] code;
659
660     package bool isPure;
661     package MDFunction* cachedFunc;
662
663     struct SwitchTable
664     {
665         package Hash!(MDValue, word) offsets;
666         package int defaultOffset = -1; // yes, this is 32 bit, it's fixed that size
667     }
668
669     package SwitchTable[] switchTables;
670
671     // Debug info.
672     package uint[] lineInfo;
673     package MDString*[] upvalNames;
674
675     struct LocVarDesc
676     {
677         package MDString* name;
678         package uint pcStart;
679         package uint pcEnd;
680         package uint reg;
681     }
682
683     package LocVarDesc[] locVarDescs;
684 }
685
686 // please don't align(1) this struct, it'll mess up the D GC when it tries to look inside for pointers.
687 struct MDVM
688 {
689     package Allocator alloc;
690
691     package <