root/trunk/minid/baselib.d

Revision 423, 21.5 kB (checked in by JarrettBillingsley, 3 weeks ago)

Fixed some formatting stuff regarding floats. The compiler will now also parse large (>32-bit) integers correctly. toJSON should no longer cause D heap allocations.

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.baselib;
25
26 import Float = tango.text.convert.Float;
27 import Integer = tango.text.convert.Integer;
28 import tango.io.Buffer;
29 import tango.io.Console;
30 import tango.io.Print;
31 import tango.io.Stdout;
32 import tango.stdc.ctype;
33 import Utf = tango.text.convert.Utf;
34
35 import minid.alloc;
36 import minid.classobj;
37 import minid.compiler;
38 import minid.ex;
39 import minid.instance;
40 import minid.interpreter;
41 import minid.misc;
42 import minid.string;
43 import minid.stringbuffer;
44 import minid.types;
45 import minid.utils;
46 import minid.vector;
47 import minid.vm;
48
49 private void register(MDThread* t, char[] name, NativeFunc func, uword numUpvals = 0)
50 {
51     newFunction(t, func, name, numUpvals);
52     newGlobal(t, name);
53 }
54
55 struct BaseLib
56 {
57 static:
58     public void init(MDThread* t)
59     {
60         register(t, "collectGarbage", &collectGarbage);
61
62         // Object
63         pushClass(t, classobj.create(t.vm.alloc, string.create(t.vm, "Object"), null));
64         newGlobal(t, "Object");
65        
66         // Vector
67         VectorObj.init(t);
68
69         // StringBuffer
70         StringBufferObj.init(t);
71
72         // Functional stuff
73         register(t, "curry", &curry);
74         register(t, "bindContext", &bindContext);
75
76         // Reflection-esque stuff
77         register(t, "findGlobal", &findGlobal);
78         register(t, "isSet", &isSet);
79         register(t, "typeof", &mdtypeof);
80         register(t, "fieldsOf", &fieldsOf);
81         register(t, "allFieldsOf", &allFieldsOf);
82         register(t, "hasField", &hasField);
83         register(t, "hasMethod", &hasMethod);
84         register(t, "findField", &findField);
85         register(t, "rawSetField", &rawSetField);
86         register(t, "rawGetField", &rawGetField);
87         register(t, "attrs", &attrs);
88         register(t, "hasAttributes", &hasAttributes);
89         register(t, "attributesOf", &attributesOf);
90         register(t, "isNull", &isParam!(MDValue.Type.Null));
91         register(t, "isBool", &isParam!(MDValue.Type.Bool));
92         register(t, "isInt", &isParam!(MDValue.Type.Int));
93         register(t, "isFloat", &isParam!(MDValue.Type.Float));
94         register(t, "isChar", &isParam!(MDValue.Type.Char));
95         register(t, "isString", &isParam!(MDValue.Type.String));
96         register(t, "isTable", &isParam!(MDValue.Type.Table));
97         register(t, "isArray", &isParam!(MDValue.Type.Array));
98         register(t, "isFunction", &isParam!(MDValue.Type.Function));
99         register(t, "isClass", &isParam!(MDValue.Type.Class));
100         register(t, "isInstance", &isParam!(MDValue.Type.Instance));
101         register(t, "isNamespace", &isParam!(MDValue.Type.Namespace));
102         register(t, "isThread", &isParam!(MDValue.Type.Thread));
103         register(t, "isNativeObj", &isParam!(MDValue.Type.NativeObj));
104         register(t, "isWeakRef", &isParam!(MDValue.Type.WeakRef));
105
106         // Conversions
107         register(t, "toString", &toString);
108         register(t, "rawToString", &rawToString);
109         register(t, "toBool", &toBool);
110         register(t, "toInt", &toInt);
111         register(t, "toFloat", &toFloat);
112         register(t, "toChar", &toChar);
113         register(t, "format", &format);
114
115         // Console IO
116         register(t, "write", &write);
117         register(t, "writeln", &writeln);
118         register(t, "writef", &writef);
119         register(t, "writefln", &writefln);
120         register(t, "readln", &readln);
121
122             newTable(t);
123         register(t, "dumpVal", &dumpVal, 1);
124
125         // Dynamic compilation stuff
126         register(t, "loadString", &loadString);
127         register(t, "eval", &eval);
128         register(t, "loadJSON", &loadJSON);
129         register(t, "toJSON", &toJSON);
130
131         // The Function type's metatable
132         newNamespace(t, "function");
133             newFunction(t, &functionEnvironment, "function.environment"); fielda(t, -2, "environment");
134             newFunction(t, &functionIsNative,    "function.isNative");    fielda(t, -2, "isNative");
135             newFunction(t, &functionNumParams,   "function.numParams");   fielda(t, -2, "numParams");
136             newFunction(t, &functionIsVararg,    "function.isVararg");    fielda(t, -2, "isVararg");
137             newFunction(t, &functionName,        "function.name");        fielda(t, -2, "name");
138         setTypeMT(t, MDValue.Type.Function);
139
140         // Weak reference stuff
141         register(t, "weakref", &weakref);
142         register(t, "deref", &deref);
143
144         newNamespace(t, "weakref");
145             newFunction(t, &weakrefDeref,        "weakref.deref");        fielda(t, -2, "deref");
146         setTypeMT(t, MDValue.Type.WeakRef);
147     }
148
149     uword collectGarbage(MDThread* t, uword numParams)
150     {
151         pushInt(t, gc(t));
152         return 1;
153     }
154    
155     // ===================================================================================================================================
156     // Functional stuff
157
158     uword curry(MDThread* t, uword numParams)
159     {
160         static uword call(MDThread* t, uword numParams)
161         {
162             getUpval(t, 0);
163             dup(t, 0);
164             getUpval(t, 1);
165             rotateAll(t, 3);
166             return rawCall(t, 1, -1);
167         }
168
169         checkParam(t, 1, MDValue.Type.Function);
170         checkAnyParam(t, 2);
171         setStackSize(t, 3);
172         newFunction(t, &call, "curryClosure", 2);
173         return 1;
174     }
175
176     uword bindContext(MDThread* t, uword numParams)
177     {
178         static uword call(MDThread* t, uword numParams)
179         {
180             getUpval(t, 0);
181             getUpval(t, 1);
182             rotateAll(t, 2);
183             return rawCall(t, 1, -1);
184         }
185
186         checkParam(t, 1, MDValue.Type.Function);
187         checkAnyParam(t, 2);
188         setStackSize(t, 3);
189         newFunction(t, &call, "boundFunction", 2);
190         return 1;
191     }
192
193     // ===================================================================================================================================
194     // Reflection-esque stuff
195
196     uword findGlobal(MDThread* t, uword numParams)
197     {
198         if(!.findGlobal(t, checkStringParam(t, 1), 1))
199             pushNull(t);
200
201         return 1;
202     }
203
204     uword isSet(MDThread* t, uword numParams)
205     {
206         if(!.findGlobal(t, checkStringParam(t, 1), 1))
207             pushBool(t, false);
208         else
209         {
210             pop(t);
211             pushBool(t, true);
212         }
213
214         return 1;
215     }
216
217     uword mdtypeof(MDThread* t, uword numParams)
218     {
219         checkAnyParam(t, 1);
220         pushString(t, MDValue.typeString(type(t, 1)));
221         return 1;
222     }
223
224     uword fieldsOf(MDThread* t, uword numParams)
225     {
226         checkAnyParam(t, 1);
227        
228         if(isClass(t, 1) || isInstance(t, 1))
229             .fieldsOf(t, 1);
230         else
231             paramTypeError(t, 1, "class|instance");
232
233         return 1;
234     }
235
236     uword allFieldsOf(MDThread* t, uword numParams)
237     {
238         // Upvalue 0 is the current object
239         // Upvalue 1 is the current index into the namespace
240         // Upvalue 2 is the duplicates table
241         static uword iter(MDThread* t, uword numParams)
242         {
243             MDInstance* i;
244             MDClass* c;
245             MDString** key = void;
246             MDValue* value = void;
247             uword index = 0;
248
249             while(true)
250             {
251                 // Get the next field
252                 getUpval(t, 0);
253
254                 getUpval(t, 1);
255                 index = cast(uword)getInt(t, -1);
256                 pop(t);
257
258                 bool haveField = void;
259
260                 if(isInstance(t, -1))
261                 {
262                     i = getInstance(t, -1);
263                     c = null;
264                     haveField = instance.next(i, index, key, value);
265                 }
266                 else
267                 {
268                     c = getClass(t, -1);
269                     i = null;
270                     haveField = classobj.next(c, index, key, value);
271                 }
272
273                 if(!haveField)
274                 {
275                     superOf(t, -1);
276
277                     if(isNull(t, -1))
278                         return 0;
279
280                     setUpval(t, 0);
281                     pushInt(t, 0);
282                     setUpval(t, 1);
283                     pop(t);
284
285                     // try again
286                     continue;
287                 }
288
289                 // See if we've already seen this field
290                 getUpval(t, 2);
291                 pushStringObj(t, *key);
292
293                 if(opin(t, -1, -2))
294                 {
295                     pushInt(t, index);
296                     setUpval(t, 1);
297                     pop(t, 3);
298
299                     // We have, try again
300                     continue;
301                 }
302
303                 // Mark the field as seen
304                 pushBool(t, true);
305                 idxa(t, -3);
306                 pop(t, 3);
307
308                 break;
309             }
310
311             pushInt(t, index);
312             setUpval(t, 1);
313
314             pushStringObj(t, *key);
315             push(t, *value);
316            
317             if(i is null)
318                 pushClass(t, c);
319             else
320                 pushInstance(t, i);
321
322             return 3;
323         }
324
325         checkAnyParam(t, 1);
326        
327         if(!isClass(t, 1) && !isInstance(t, 1))
328             paramTypeError(t, 1, "class|instance");
329
330         dup(t, 1);
331         pushInt(t, 0);
332         newTable(t);
333         newFunction(t, &iter, "allFieldsOfIter", 3);
334         return 1;
335     }
336
337     uword hasField(MDThread* t, uword numParams)
338     {
339         checkAnyParam(t, 1);
340         auto n = checkStringParam(t, 2);
341         pushBool(t, .hasField(t, 1, n));
342         return 1;
343     }
344
345     uword hasMethod(MDThread* t, uword numParams)
346     {
347         checkAnyParam(t, 1);
348         auto n = checkStringParam(t, 2);
349         pushBool(t, .hasMethod(t, 1, n));
350         return 1;
351     }
352
353     uword findField(MDThread* t, uword numParams)
354     {
355         checkAnyParam(t, 1);
356        
357         if(!isInstance(t, 1) && !isClass(t, 1))
358             paramTypeError(t, 1, "class|instance");
359
360         checkStringParam(t, 2);
361
362         while(!isNull(t, 1))
363         {
364             auto fields = .fieldsOf(t, 1);
365
366             if(opin(t, 2, fields))
367             {
368                 dup(t, 1);
369                 return 1;
370             }
371
372             superOf(t, 1);
373             swap(t, 1);
374             pop(t, 2);
375         }
376
377         return 0;
378     }
379
380     uword rawSetField(MDThread* t, uword numParams)
381     {
382         checkInstParam(t, 1);
383         checkStringParam(t, 2);
384         checkAnyParam(t, 3);
385         dup(t, 2);
386         dup(t, 3);
387         fielda(t, 1, true);
388         return 0;
389     }
390
391     uword rawGetField(MDThread* t, uword numParams)
392     {
393         checkInstParam(t, 1);
394         checkStringParam(t, 2);
395         dup(t, 2);
396         field(t, 1, true);
397         return 1;
398     }
399
400     uword attrs(MDThread* t, uword numParams)
401     {
402         checkAnyParam(t, 1);
403         checkParam(t, 2, MDValue.Type.Table);
404         dup(t, 2);
405         setAttributes(t, 1);
406         dup(t, 1);
407         return 1;
408     }
409
410     uword hasAttributes(MDThread* t, uword numParams)
411     {
412         checkAnyParam(t, 1);
413         pushBool(t, .hasAttributes(t, 1));
414         return 1;
415     }
416
417     uword attributesOf(MDThread* t, uword numParams)
418     {
419         checkAnyParam(t, 1);
420         getAttributes(t, 1);
421         return 1;
422     }
423
424     uword isParam(MDValue.Type Type)(MDThread* t, uword numParams)
425     {
426         checkAnyParam(t, 1);
427         pushBool(t, type(t, 1) == Type);
428         return 1;
429     }
430
431     // ===================================================================================================================================
432     // Conversions
433
434     uword toString(MDThread* t, uword numParams)
435     {
436         checkAnyParam(t, 1);
437
438         if(isInt(t, 1))
439         {
440             char[1] style = "d";
441
442             if(numParams > 1)
443                 style[0] = getChar(t, 2);
444
445             char[80] buffer = void;
446             pushString(t, safeCode(t, Integer.format(buffer, getInt(t, 1), style)));
447         }
448         else
449             pushToString(t, 1);
450
451         return 1;
452     }
453
454     uword rawToString(MDThread* t, uword numParams)
455     {
456         checkAnyParam(t, 1);
457         pushToString(t, 1, true);
458         return 1;
459     }
460
461     uword toBool(MDThread* t, uword numParams)
462     {
463         checkAnyParam(t, 1);
464         pushBool(t, isTrue(t, 1));
465         return 1;
466     }
467
468     uword toInt(MDThread* t, uword numParams)
469     {
470         checkAnyParam(t, 1);
471
472         switch(type(t, 1))
473         {
474             case MDValue.Type.Bool:   pushInt(t, cast(mdint)getBool(t, 1)); break;
475             case MDValue.Type.Int:    dup(t, 1); break;
476             case MDValue.Type.Float:  pushInt(t, cast(mdint)getFloat(t, 1)); break;
477             case MDValue.Type.Char:   pushInt(t, cast(mdint)getChar(t, 1)); break;
478             case MDValue.Type.String: pushInt(t, safeCode(t, cast(mdint)Integer.toLong(getString(t, 1), 10))); break;
479
480             default:
481                 pushTypeString(t, 1);
482                 throwException(t, "Cannot convert type '{}' to int", getString(t, -1));
483         }
484
485         return 1;
486     }
487
488     uword toFloat(MDThread* t, uword numParams)
489     {
490         checkAnyParam(t, 1);
491
492         switch(type(t, 1))
493         {
494             case MDValue.Type.Bool: pushFloat(t, cast(mdfloat)getBool(t, 1)); break;
495             case MDValue.Type.Int: pushFloat(t, cast(mdfloat)getInt(t, 1)); break;
496             case MDValue.Type.Float: dup(t, 1); break;
497             case MDValue.Type.Char: pushFloat(t, cast(mdfloat)getChar(t, 1)); break;
498             case MDValue.Type.String: pushFloat(t, safeCode(t, cast(mdfloat)Float.toFloat(getString(t, 1)))); break;
499
500             default:
501                 pushTypeString(t, 1);
502                 throwException(t, "Cannot convert type '{}' to float", getString(t, -1));
503         }
504
505         return 1;
506     }
507
508     uword toChar(MDThread* t, uword numParams)
509     {
510         pushChar(t, cast(dchar)checkIntParam(t, 1));
511         return 1;
512     }
513
514     uword format(MDThread* t, uword numParams)
515     {
516         auto buf = StrBuffer(t);
517         formatImpl(t, numParams, &buf.sink);
518         buf.finish();
519         return 1;
520     }
521
522     // ===================================================================================================================================
523     // Console IO
524
525     uword write(MDThread* t, uword numParams)
526     {
527         for(uword i = 1; i <= numParams; i++)
528         {
529             pushToString(t, i);
530             Stdout(getString(t, -1));
531         }
532
533         Stdout.flush;
534         return 0;
535     }
536
537     uword writeln(MDThread* t, uword numParams)
538     {
539         for(uword i = 1; i <= numParams; i++)
540         {
541             pushToString(t, i);
542             Stdout(getString(t, -1));
543         }
544
545         Stdout.newline;
546         return 0;
547     }
548
549     uword writef(MDThread* t, uword numParams)
550     {
551         uint sink(char[] data