supernova: fix for small audio vector sizes
[supercollider.git] / lang / LangPrimSource / PyrPrimitive.cpp
blob24dc38d3cfba315817c5ad038b760522a4debf30
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <stdlib.h>
22 #include <string.h>
23 #include <math.h>
24 #include "PyrKernel.h"
25 #include "PyrObject.h"
26 #include "PyrPrimitive.h"
27 #include "PyrPrimitiveProto.h"
28 #include "PyrSignal.h"
29 #include "PyrSched.h"
30 #include "PyrSignalPrim.h"
31 #include "PyrFilePrim.h"
32 #include "PyrMathPrim.h"
33 #include "PyrListPrim.h"
34 #include "Opcodes.h"
35 #include "SC_InlineUnaryOp.h"
36 #include "SC_InlineBinaryOp.h"
37 #include "PyrMessage.h"
38 #include "PyrParseNode.h"
39 #include "PyrLexer.h"
40 #include "PyrKernelProto.h"
41 #include "PyrInterpreter.h"
42 #include "PyrObjectProto.h"
43 #include "PyrArchiverT.h"
44 #include "PyrDeepCopier.h"
45 #include "PyrDeepFreezer.h"
46 //#include "Wacom.h"
47 #include "InitAlloc.h"
48 #include "SC_LibraryConfig.h"
49 #include "SC_DirUtils.h"
52 #ifdef SC_WIN32
53 # include <direct.h>
54 #else
55 # include <sys/param.h>
56 #endif
58 #ifdef SC_QT
59 # include "QtCollider.h"
60 #endif
62 int yyparse();
64 extern bool gTraceInterpreter;
65 PyrSymbol *s_recvmsg;
67 void initPatternPrimitives();
69 typedef struct {
70 PrimitiveHandler func;
71 PyrSymbol* name;
72 unsigned short base;
73 unsigned char numArgs;
74 unsigned char varArgs;
75 unsigned char keyArgs;
76 } PrimitiveDef;
78 typedef struct {
79 int size, maxsize;
80 PrimitiveDef *table;
81 } PrimitiveTable;
83 extern PrimitiveTable gPrimitiveTable;
85 extern PyrSlot o_nullframe;
88 int getPrimitiveNumArgs(int index)
90 return gPrimitiveTable.table[index].numArgs;
93 PyrSymbol* getPrimitiveName(int index)
95 return gPrimitiveTable.table[index].name;
98 int slotStrLen(PyrSlot *slot) {
99 if (IsSym(slot)) {
100 return slotRawSymbol(slot)->length;
101 } else if (isKindOfSlot(slot, class_string)) {
102 return slotRawObject(slot)->size;
104 return -1;
107 int slotStrVal(PyrSlot *slot, char *str, int maxlen)
109 if (IsSym(slot)) {
110 strncpy(str, slotRawSymbol(slot)->name, maxlen);
111 return errNone;
112 } else if (isKindOfSlot(slot, class_string)) {
113 int len;
114 len = sc_min(maxlen-1, slotRawObject(slot)->size);
115 memcpy(str, slotRawString(slot)->s, len);
116 str[len] = 0;
117 return errNone;
119 return errWrongType;
122 int slotPStrVal(PyrSlot *slot, unsigned char *str)
124 if (IsSym(slot)) {
125 strncpy((char*)str+1, slotRawSymbol(slot)->name, 255);
126 str[0] = slotRawSymbol(slot)->length;
127 return errNone;
128 } else if (isKindOfSlot(slot, class_string)) {
129 int len;
130 len = sc_min(255, slotRawObject(slot)->size);
131 memcpy(str+1, slotRawString(slot)->s, len);
132 str[0] = len;
133 return errNone;
135 return errWrongType;
138 int instVarAt(struct VMGlobals *g, int numArgsPushed)
140 PyrSlot *a, *b;
141 int index;
143 a = g->sp - 1;
144 b = g->sp;
146 if (NotObj(a)) return errWrongType;
148 PyrObject *obj = slotRawObject(a);
150 if (IsInt(b)) {
151 index = slotRawInt(b);
152 if (index < 0 || index >= obj->size) return errIndexOutOfRange;
153 slotCopy(a,&obj->slots[index]);
154 } else if (IsSym(b)) {
155 PyrSlot *instVarNamesSlot = &obj->classptr->instVarNames;
156 if (!isKindOfSlot(instVarNamesSlot, class_symbolarray)) return errFailed;
157 PyrSymbolArray *instVarNames = slotRawSymbolArray(instVarNamesSlot);
158 PyrSymbol **names = instVarNames->symbols;
159 PyrSymbol *name = slotRawSymbol(b);
160 for (int i=0; i<instVarNames->size; ++i) {
161 if (names[i] == name) {
162 slotCopy(a,&obj->slots[i]);
163 return errNone;
166 return errFailed;
167 } else return errWrongType;
168 return errNone;
171 int instVarPut(struct VMGlobals *g, int numArgsPushed)
173 PyrSlot *a, *b, *c, *slot;
174 int index;
175 PyrObject *obj;
177 a = g->sp - 2;
178 b = g->sp - 1;
179 c = g->sp;
181 if (NotObj(a)) return errWrongType;
182 obj = slotRawObject(a);
183 if (obj->obj_flags & obj_immutable) return errImmutableObject;
185 if (IsInt(b)) {
186 index = slotRawInt(b);
187 if (index < 0 || index >= obj->size) return errIndexOutOfRange;
188 slot = obj->slots + index;
189 slotCopy(slot,c);
190 g->gc->GCWrite(obj, slot);
191 } else if (IsSym(b)) {
192 PyrSlot *instVarNamesSlot = &obj->classptr->instVarNames;
193 if (!IsObj(instVarNamesSlot)) return errFailed;
194 PyrSymbolArray *instVarNames = slotRawSymbolArray(instVarNamesSlot);
195 PyrSymbol **names = instVarNames->symbols;
196 PyrSymbol *name = slotRawSymbol(b);
197 for (int i=0; i<instVarNames->size; ++i) {
198 if (names[i] == name) {
199 slot = obj->slots + i;
200 slotCopy(slot,c);
201 g->gc->GCWrite(obj, slot);
202 return errNone;
205 post("WARNING: %s instVarPut '%s' failed.\n", slotRawSymbol(&obj->classptr->name)->name, name->name);
206 return errNone;
207 } else return errWrongType;
208 return errNone;
211 int instVarSize(struct VMGlobals *g, int numArgsPushed)
213 PyrSlot *a;
214 PyrObject *obj;
216 a = g->sp;
217 if (NotObj(a)) {
218 SetInt(a, 0);
219 return errNone;
221 obj = slotRawObject(a);
222 if (obj->obj_format == obj_notindexed) {
223 SetInt(a, obj->size);
224 } else {
225 SetInt(a, 0);
227 return errNone;
231 int objectHash(struct VMGlobals *g, int numArgsPushed)
233 PyrSlot *a;
234 int hash;
236 a = g->sp;
238 hash = calcHash(a);
239 SetInt(a, hash);
240 return errNone;
243 int objectClass(struct VMGlobals *g, int numArgsPushed)
245 PyrSlot *a;
246 PyrClass *classobj;
248 a = g->sp;
249 classobj = classOfSlot(a);
250 SetObject(a, classobj);
251 return errNone;
254 int prPrimitiveError(struct VMGlobals *g, int numArgsPushed)
256 PyrSlot *a;
258 a = g->sp;
259 slotCopy(a,&g->thread->primitiveError);
260 return errNone;
263 int prStackDepth(struct VMGlobals *g, int numArgsPushed);
264 int prStackDepth(struct VMGlobals *g, int numArgsPushed)
266 PyrSlot *a;
268 a = g->sp;
269 SetInt(a, g->gc->StackDepth());
270 return errNone;
273 extern void DumpStack(VMGlobals *g, PyrSlot *sp);
275 int prDumpStack(struct VMGlobals *g, int numArgsPushed)
277 DumpStack(g, g->sp);
278 return errNone;
281 void DumpDetailedBackTrace(VMGlobals *g);
282 int prDumpDetailedBackTrace(struct VMGlobals *g, int numArgsPushed);
283 int prDumpDetailedBackTrace(struct VMGlobals *g, int numArgsPushed)
285 DumpDetailedBackTrace(g);
286 return errNone;
289 int prPrimitiveErrorString(struct VMGlobals *g, int numArgsPushed)
291 PyrSlot *a;
292 PyrString *string;
293 const char *str;
295 a = g->sp;
296 switch (slotRawInt(&g->thread->primitiveError)) {
297 case errReturn : str = "Return (not an error)."; break;
298 case errNone : str = "No Error"; break;
299 case errFailed : str = "Failed."; break;
300 case errBadPrimitive : str = "Bad Primitive."; break;
301 case errWrongType : str = "Wrong type."; break;
302 case errIndexNotAnInteger : str = "Index not an Integer"; break;
303 case errIndexOutOfRange : str = "Index out of range."; break;
304 case errImmutableObject : str = "Attempted write to immutable object."; break;
305 case errNotAnIndexableObject : str = "Not an indexable object."; break;
306 case errStackOverflow : str = "Stack overflow."; break;
307 case errOutOfMemory : str = "Out of memory."; break;
308 case errCantCallOS : str = "Operation cannot be called from this Process. Try using AppClock instead of SystemClock."; break;
310 default : str = "Failed.";
312 string = newPyrString(g->gc, str, 0, true);
313 SetObject(a, string);
314 return errNone;
319 int prPostString(struct VMGlobals *g, int numArgsPushed)
321 PyrSlot *a;
323 a = g->sp;
324 //if (NotObj(a)) return errWrongType;
325 // assume it is a string!
326 postText(slotRawString(a)->s, slotRawString(a)->size);
327 return errNone;
330 int prPostLine(struct VMGlobals *g, int numArgsPushed)
332 PyrSlot *a;
334 a = g->sp;
335 //if (NotObj(a)) return errWrongType;
336 // assume it is a string!
337 postText(slotRawString(a)->s, slotRawString(a)->size);
338 postChar('\n');
339 return errNone;
342 int prDebugger(struct VMGlobals *g, int numArgsPushed)
344 PyrSlot *a;
346 a = g->sp;
347 //Debugger();
348 return errNone;
354 int prObjectString(struct VMGlobals *g, int numArgsPushed)
356 PyrSlot *a;
357 PyrString *string;
358 char str[256];
360 a = g->sp;
361 if (IsSym(a)) {
362 string = newPyrString(g->gc, slotRawSymbol(a)->name, 0, true);
363 SetObject(a, string);
364 return errNone;
365 } else if (postString(a, str)) {
366 string = newPyrString(g->gc, str, 0, true);
367 SetObject(a, string);
368 return errNone;
369 } else {
370 return errFailed;
374 int prFloat_AsStringPrec(struct VMGlobals *g, int numArgsPushed);
375 int prFloat_AsStringPrec(struct VMGlobals *g, int numArgsPushed)
377 PyrSlot *a = g->sp - 1;
378 PyrSlot *b = g->sp;
380 int precision;
381 int err = slotIntVal(b, &precision);
382 if (err) return err;
384 char fmt[8], str[256];
385 sprintf(fmt, "%%.%dg", precision);
386 sprintf(str, fmt, slotRawFloat(a));
388 PyrString *string = newPyrString(g->gc, str, 0, true);
389 SetObject(a, string);
390 return errNone;
394 int prAsCompileString(struct VMGlobals *g, int numArgsPushed);
395 int prAsCompileString(struct VMGlobals *g, int numArgsPushed)
397 PyrSlot *a;
398 PyrString *string;
399 int err = errNone;
401 a = g->sp;
402 if (IsSym(a)) {
403 int len = strlen(slotRawSymbol(a)->name) + 1;
404 if (len < 255) {
405 char str[256];
406 sprintf(str, "'%s'", slotRawSymbol(a)->name);
407 string = newPyrString(g->gc, str, 0, true);
408 } else {
409 char *str = (char*)malloc(len+2);
410 sprintf(str, "'%s'", slotRawSymbol(a)->name);
411 string = newPyrString(g->gc, str, 0, true);
412 free(str);
414 } else {
415 char str[256];
416 err = asCompileString(a, str);
417 if (err) return err;
418 string = newPyrString(g->gc, str, 0, true);
420 SetObject(a, string);
421 return err;
425 int prClassString(struct VMGlobals *g, int numArgsPushed)
427 PyrSlot *a;
428 PyrClass *classobj;
429 PyrString *string;
431 a = g->sp;
432 classobj = classOfSlot(a);
433 string = newPyrString(g->gc, slotRawSymbol(&classobj->name)->name, 0, true);
434 SetObject(a, string);
435 return errNone;
439 int prPrimName(struct VMGlobals *g, int numArgsPushed)
441 PyrSlot *a;
442 PyrThread *thread;
444 a = g->sp;
445 thread = slotRawThread(a);
446 if (slotRawInt(&thread->primitiveIndex) <= gPrimitiveTable.size) {
447 SetSymbol(a, gPrimitiveTable.table[slotRawInt(&thread->primitiveIndex)].name);
448 } else {
449 SetSymbol(a, s_none);
451 return errNone;
454 int objectIsKindOf(struct VMGlobals *g, int numArgsPushed)
456 PyrSlot *a, *b;
457 PyrClass *classobj, *testclass;
458 int objClassIndex, testClassIndex, maxSubclassIndex;
460 a = g->sp - 1;
461 b = g->sp;
463 if (NotObj(b)) return errWrongType;
464 testclass = (PyrClass*)slotRawObject(b);
465 classobj = classOfSlot(a);
466 #if 0
467 while (classobj) {
468 if (classobj == testclass) {
469 SetTrue(a);
470 return errNone;
472 classobj = slotRawSymbol(&classobj->superclass)->u.classobj;
474 SetFalse(a);
475 #else
476 // constant time lookup method:
478 objClassIndex = slotRawInt(&classobj->classIndex);
479 testClassIndex = slotRawInt(&testclass->classIndex);
480 maxSubclassIndex = slotRawInt(&testclass->maxSubclassIndex);
482 /*post("%s %s\n", slotRawSymbol(&classobj->name)->name, testclass->name.us->name);
483 post("objClassIndex %d\n", objClassIndex);
484 post("testClassIndex %d\n", testClassIndex);
485 post("maxSubclassIndex %d\n", maxSubclassIndex);*/
487 if (objClassIndex >= testClassIndex && objClassIndex <= maxSubclassIndex) {
488 SetTrue(a);
489 return errNone;
490 } else {
491 SetFalse(a);
492 return errNone;
495 #endif
496 return errNone;
500 int objectIsMemberOf(struct VMGlobals *g, int numArgsPushed)
502 PyrSlot *a, *b;
503 PyrClass *classobj, *testclass;
505 a = g->sp - 1;
506 b = g->sp;
508 if (NotObj(b)) return errWrongType;
509 testclass = (PyrClass*)slotRawObject(b);
510 classobj = classOfSlot(a);
511 if (classobj == testclass) {
512 SetTrue(a);
513 } else {
514 SetFalse(a);
516 return errNone;
519 int objectIdentical(struct VMGlobals *g, int numArgsPushed)
521 PyrSlot *a, *b;
523 a = g->sp - 1;
524 b = g->sp;
526 if (SlotEq(a, b))
527 SetTrue(a);
528 else
529 SetFalse(a);
530 return errNone;
533 int objectNotIdentical(struct VMGlobals *g, int numArgsPushed)
535 PyrSlot *a, *b;
537 a = g->sp - 1;
538 b = g->sp;
540 if ( !SlotEq(a, b) )
541 SetTrue(a);
542 else
543 SetFalse(a);
544 return errNone;
548 int basicNewClear(struct VMGlobals *g, int numArgsPushed)
550 PyrSlot *a, *b;
551 int size;
552 PyrClass *classobj;
553 PyrObject *newobj;
555 a = g->sp - 1;
556 b = g->sp;
558 if (NotObj(a)) return errWrongType;
559 classobj = (PyrClass*)slotRawObject(a);
560 if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) {
561 // create an indexable object
562 if (NotInt(b)) {
563 if (IsFloat(b)) {
564 size = (int)slotRawFloat(b);
565 } else if (NotNil(b)) return errIndexNotAnInteger;
566 else size = 8;
567 } else {
568 size = slotRawInt(b);
570 if (size < 0) size = 0;
571 } else {
572 size = 0;
574 newobj = instantiateObject(g->gc, classobj, size, true, true);
575 SetObject(a, newobj);
576 return errNone;
579 int basicNewCopyArgsToInstanceVars(struct VMGlobals *g, int numArgsPushed);
580 int basicNewCopyArgsToInstanceVars(struct VMGlobals *g, int numArgsPushed)
582 PyrSlot *a, *b;
583 PyrClass *classobj;
584 PyrObject *newobj;
586 a = g->sp - numArgsPushed + 1;
587 b = a + 1;
589 if (NotObj(a)) return errWrongType;
590 classobj = (PyrClass*)slotRawObject(a);
591 if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) {
592 error("CopyArgs : object has no instance variables.\n");
593 return errFailed;
595 newobj = instantiateObject(g->gc, classobj, 0, true, true);
596 SetObject(a, newobj);
598 int length = sc_min(numArgsPushed-1, newobj->size);
599 for (int i=0; i<length; ++i) {
600 slotCopy(&newobj->slots[i],&b[i]);
603 return errNone;
608 int basicNew(struct VMGlobals *g, int numArgsPushed)
610 PyrSlot *a, *b;
611 int size;
612 PyrClass *classobj;
613 PyrObject *newobj;
615 a = g->sp - 1;
616 b = g->sp;
618 if (NotObj(a)) return errWrongType;
619 classobj = (PyrClass*)slotRawObject(a);
620 if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) {
621 // create an indexable object
622 if (NotInt(b)) {
623 if (IsFloat(b)) {
624 size = (int)slotRawFloat(b);
625 } else if (NotNil(b)) return errIndexNotAnInteger;
626 else size = 8;
627 } else {
628 size = slotRawInt(b);
630 if (size < 0) size = 0;
631 } else {
632 size = 0;
634 newobj = instantiateObject(g->gc, classobj, size, false, true);
635 SetObject(a, newobj);
636 return errNone;
640 bool isClosed(PyrBlock* fundef);
641 bool isClosed(PyrBlock* fundef)
643 return IsNil(&fundef->contextDef) && fundef->classptr == class_fundef;
646 bool isWithinClosed(PyrBlock* fundef);
647 bool isWithinClosed(PyrBlock* fundef)
649 while (fundef) {
650 if (isClosed(fundef)) return true;
651 fundef = slotRawBlock(&fundef->contextDef);
653 return false;
656 int prFunctionDefAsFunction(struct VMGlobals *g, int numArgsPushed);
657 int prFunctionDefAsFunction(struct VMGlobals *g, int numArgsPushed)
659 PyrSlot *a = g->sp;
661 if (!isClosed(slotRawBlock(a))) {
662 dumpObjectSlot(a);
663 error("Only closed FunctionDef may be converted to a Function using asFunction.\n");
664 return errFailed;
667 PyrClosure* closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, true);
669 closure->classptr = gSpecialClasses[op_class_func]->u.classobj;
670 closure->size = 2;
671 slotCopy(&closure->block,a);
672 slotCopy(&closure->context,&slotRawInterpreter(&g->process->interpreter)->context);
673 SetObject(a, closure);
674 return errNone;
677 int prFunctionDefDumpContexts(struct VMGlobals *g, int numArgsPushed);
678 int prFunctionDefDumpContexts(struct VMGlobals *g, int numArgsPushed)
680 PyrSlot *a = g->sp;
682 int i=0;
683 while (slotRawBlock(a)) {
684 post("%2d context %s %p\n", i++, slotRawSymbol(&slotRawObject(a)->classptr->name)->name, slotRawInt(&slotRawBlock(a)->contextDef));
685 a = &slotRawBlock(a)->contextDef;
687 return errNone;
692 int prFunctionDefIsClosed(struct VMGlobals *g, int numArgsPushed);
693 int prFunctionDefIsClosed(struct VMGlobals *g, int numArgsPushed)
695 PyrSlot *a = g->sp;
696 PyrBlock *block = slotRawBlock(a);
698 SetBool(a, isClosed(block));
699 return errNone;
702 int prFunctionDefIsWithinClosed(struct VMGlobals *g, int numArgsPushed);
703 int prFunctionDefIsWithinClosed(struct VMGlobals *g, int numArgsPushed)
705 PyrSlot *a = g->sp;
706 PyrBlock *block = slotRawBlock(a);
708 SetBool(a, isWithinClosed(block));
709 return errNone;
713 void reallocStack(struct VMGlobals *g, int stackNeeded, int stackDepth)
715 //PyrThread *thread = g->thread;
716 PyrGC *gc = g->gc;
717 int newStackSize = NEXTPOWEROFTWO(stackNeeded);
719 PyrObject* array = newPyrArray(gc, newStackSize, 0, false);
720 memcpy(array->slots, gc->Stack()->slots, stackDepth * sizeof(PyrSlot));
721 gc->SetStack(array);
722 gc->ToBlack(gc->Stack());
723 g->sp = array->slots + stackDepth - 1;
727 int blockValueArray(struct VMGlobals *g, int numArgsPushed)
729 PyrSlot *b;
730 PyrObject *array;
731 PyrList *list;
732 PyrSlot *pslot, *qslot;
733 int m, size;
735 //a = g->sp - numArgsPushed + 1;
736 b = g->sp;
738 if (IsObj(b)) {
739 if (slotRawObject(b)->classptr == class_array) {
740 array = (PyrObject*)slotRawObject(b);
741 above:
742 size = array->size;
744 PyrObject *stack = g->gc->Stack();
745 int stackDepth = g->sp - stack->slots + 1;
746 int stackSize = ARRAYMAXINDEXSIZE(stack);
747 int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations.
748 if (stackNeeded > stackSize) {
749 reallocStack(g, stackNeeded, stackDepth);
750 b = g->sp;
753 pslot = array->slots - 1;
754 qslot = b - 1;
755 //pend = (double*)(pslot + size);
756 //while (pslot<pend) slotCopy(++qslot, ++pslot);
757 for (m=0; m<size; ++m) slotCopy(++qslot, ++pslot);
759 g->sp += size - 1;
760 return blockValue(g, size+numArgsPushed-1);
762 } else if (slotRawObject(b)->classptr == class_list) {
763 list = slotRawList(b);
764 if (NotObj(&list->array)) return errWrongType;
765 array = slotRawObject(&list->array);
766 if (array->classptr != class_array) return errWrongType;
767 goto above;
768 } else { // last arg is not a list or array, so pass as normal
769 return blockValue(g, numArgsPushed);
771 } else {
772 return blockValue(g, numArgsPushed);
776 int blockValueEnvir(struct VMGlobals *g, int numArgsPushed);
778 int blockValueArrayEnvir(struct VMGlobals *g, int numArgsPushed);
779 int blockValueArrayEnvir(struct VMGlobals *g, int numArgsPushed)
781 PyrSlot *b;
782 PyrObject *array;
783 PyrList *list;
784 PyrSlot *pslot, *qslot;
785 int m, size;
787 //a = g->sp - numArgsPushed + 1;
788 b = g->sp;
790 if (IsObj(b)) {
791 if (slotRawObject(b)->classptr == class_array) {
792 array = (PyrObject*)slotRawObject(b);
793 above:
794 size = array->size;
796 PyrObject *stack = g->gc->Stack();
797 int stackDepth = g->sp - stack->slots + 1;
798 int stackSize = ARRAYMAXINDEXSIZE(stack);
799 int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations.
800 if (stackNeeded > stackSize) {
801 reallocStack(g, stackNeeded, stackDepth);
802 b = g->sp;
805 pslot = array->slots - 1;
806 qslot = b - 1;
807 //pend = (double*)(pslot + size);
808 //while (pslot<pend) slotCopy(++qslot, ++pslot);
809 for (m=0; m<size; ++m) slotCopy(++qslot, ++pslot);
811 g->sp += size - 1;
812 return blockValueEnvir(g, size+numArgsPushed-1);
814 } else if (slotRawObject(b)->classptr == class_list) {
815 list = slotRawList(b);
816 if (NotObj(&list->array)) return errWrongType;
817 array = slotRawObject(&list->array);
818 if (array->classptr != class_array) return errWrongType;
819 goto above;
820 } else { // last arg is not a list or array, so pass as normal
821 return blockValueEnvir(g, numArgsPushed);
823 } else {
824 return blockValueEnvir(g, numArgsPushed);
828 int blockValue(struct VMGlobals *g, int numArgsPushed)
830 PyrSlot *args;
831 PyrSlot *vars;
832 PyrFrame *frame;
833 PyrSlot *pslot, *qslot;
834 PyrSlot *rslot;
835 PyrObject *proto;
836 int i, m, mmax, numtemps;
837 PyrBlock *block;
838 PyrFrame *context;
839 PyrFrame *caller;
840 PyrFrame *homeContext;
841 PyrClosure *closure;
842 PyrMethodRaw *methraw;
844 #if TAILCALLOPTIMIZE
845 int tailCall = g->tailCall;
846 if (tailCall) {
847 if (tailCall == 1) {
848 returnFromMethod(g);
849 } else {
850 returnFromBlock(g);
853 #endif
855 g->execMethod = 30;
857 args = g->sp - numArgsPushed + 1;
859 numArgsPushed -- ;
860 g->numpop = 0;
862 closure = (PyrClosure*)slotRawObject(args);
863 block = slotRawBlock(&closure->block);
864 context = slotRawFrame(&closure->context);
866 proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : 0;
867 methraw = METHRAW(block);
868 numtemps = methraw->numtemps;
869 caller = g->frame;
871 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
872 vars = frame->vars - 1;
873 frame->classptr = class_frame;
874 frame->size = FRAMESIZE + numtemps;
875 SetObject(&frame->method, block);
876 slotCopy(&frame->homeContext,&context->homeContext);
877 slotCopy(&frame->context,&closure->context);
879 if (caller) {
880 SetPtr(&caller->ip, g->ip);
881 SetObject(&frame->caller, g->frame);
882 } else {
883 SetInt(&frame->caller, 0);
885 SetPtr(&frame->ip, 0);
888 g->sp = args - 1;
889 g->ip = slotRawInt8Array(&block->code)->b - 1;
890 g->frame = frame;
891 g->block = block;
893 if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
894 /* push all args to frame */
895 qslot = args;
896 pslot = vars;
898 for (m=0; m<numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
900 /* push default arg values */
901 pslot = vars + numArgsPushed;
902 qslot = proto->slots + numArgsPushed - 1;
903 for (m=0; m<numtemps - numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
904 } else if (methraw->varargs) {
905 PyrObject *list;
906 PyrSlot *lslot;
908 /* push all normal args to frame */
909 qslot = args;
910 pslot = vars;
911 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
913 /* push list */
914 i = numArgsPushed - methraw->numargs;
915 list = newPyrArray(g->gc, i, 0, false);
916 list->size = i;
918 rslot = pslot+1;
919 SetObject(rslot, list);
920 //SetObject(vars + methraw->numargs + 1, list);
922 /* put extra args into list */
923 lslot = list->slots - 1;
924 // fixed and raw sizes are zero
925 for (m=0; m<i; ++m) slotCopy(++lslot, ++qslot);
927 if (methraw->numvars) {
928 /* push default keyword and var values */
929 pslot = vars + methraw->numargs + 1;
930 qslot = proto->slots + methraw->numargs;
931 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
933 } else {
934 if (methraw->numargs) {
935 /* push all args to frame */
936 qslot = args;
937 pslot = vars;
938 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
940 if (methraw->numvars) {
941 /* push default keyword and var values */
942 pslot = vars + methraw->numargs;
943 qslot = proto->slots + methraw->numargs - 1;
944 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
948 homeContext = slotRawFrame(&frame->homeContext);
949 if (homeContext) {
950 PyrMethodRaw *methraw;
951 g->method = slotRawMethod(&homeContext->method);
952 methraw = METHRAW(g->method);
953 slotCopy(&g->receiver,&homeContext->vars[0]);
954 } else {
955 slotCopy(&g->receiver,&g->process->interpreter);
958 return errNone;
961 int blockValueWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed);
962 int blockValueWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed)
964 PyrSlot *args;
965 PyrSlot *vars;
966 PyrFrame *frame;
967 PyrSlot *pslot, *qslot;
968 PyrSlot *rslot;
969 PyrObject *proto;
970 int i, j, m, mmax, numtemps, numArgsPushed;
971 PyrBlock *block;
972 PyrFrame *context;
973 PyrFrame *caller;
974 PyrFrame *homeContext;
975 PyrClosure *closure;
976 PyrMethodRaw *methraw;
978 #if TAILCALLOPTIMIZE
979 int tailCall = g->tailCall;
980 if (tailCall) {
981 if (tailCall == 1) {
982 returnFromMethod(g);
983 } else {
984 returnFromBlock(g);
987 #endif
989 g->execMethod = 40;
991 args = g->sp - allArgsPushed + 1;
993 allArgsPushed -- ;
994 g->numpop = 0;
996 closure = (PyrClosure*)slotRawObject(args);
997 block = slotRawBlock(&closure->block);
998 context = slotRawFrame(&closure->context);
1000 proto = slotRawObject(&block->prototypeFrame);
1001 methraw = METHRAW(block);
1002 numtemps = methraw->numtemps;
1003 caller = g->frame;
1004 numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1);
1006 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
1007 vars = frame->vars - 1;
1008 frame->classptr = class_frame;
1009 frame->size = FRAMESIZE + numtemps;
1010 SetObject(&frame->method, block);
1011 slotCopy(&frame->homeContext,&context->homeContext);
1012 slotCopy(&frame->context,&closure->context);
1014 if (caller) {
1015 SetPtr(&caller->ip, g->ip);
1016 SetObject(&frame->caller, g->frame);
1017 } else {
1018 SetInt(&frame->caller, 0);
1020 SetPtr(&frame->ip, 0);
1022 g->sp = args - 1;
1023 g->ip = slotRawInt8Array(&block->code)->b - 1;
1024 g->frame = frame;
1025 g->block = block;
1027 if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
1028 /* push all args to frame */
1029 qslot = args;
1030 pslot = vars;
1032 for (m=0; m<numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1034 /* push default arg values */
1035 pslot = vars + numArgsPushed;
1036 qslot = proto->slots + numArgsPushed - 1;
1037 for (m=0; m<numtemps - numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1038 } else if (methraw->varargs) {
1039 PyrObject *list;
1040 PyrSlot *lslot;
1042 /* push all normal args to frame */
1043 qslot = args;
1044 pslot = vars;
1045 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1047 /* push list */
1048 i = numArgsPushed - methraw->numargs;
1049 list = newPyrArray(g->gc, i, 0, false);
1050 list->size = i;
1052 rslot = pslot+1;
1053 SetObject(rslot, list);
1054 //SetObject(vars + methraw->numargs + 1, list);
1056 /* put extra args into list */
1057 lslot = list->slots - 1;
1058 // fixed and raw sizes are zero
1059 //lend = lslot + i;
1060 //while (lslot < lend) slotCopy(++lslot, ++qslot);
1061 for (m=0; m<i; ++m) slotCopy(++lslot, ++qslot);
1063 if (methraw->numvars) {
1064 /* push default keyword and var values */
1065 pslot = vars + methraw->numargs + 1;
1066 qslot = proto->slots + methraw->numargs;
1067 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1069 } else {
1070 if (methraw->numargs) {
1071 /* push all args to frame */
1072 qslot = args;
1073 pslot = vars;
1074 //pend = pslot + methraw->numargs;
1075 //while (pslot < pend) slotCopy(++pslot, ++qslot);
1076 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1078 if (methraw->numvars) {
1079 /* push default keyword and var values */
1080 pslot = vars + methraw->numargs;
1081 qslot = proto->slots + methraw->numargs - 1;
1082 //pend = pslot + methraw->numvars;
1083 //while (pslot<pend) slotCopy(++pslot, ++qslot);
1084 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1087 // do keyword lookup:
1088 if (numKeyArgsPushed && methraw->posargs) {
1089 PyrSlot *key;
1090 PyrSymbol **name0, **name;
1091 name0 = slotRawSymbolArray(&block->argNames)->symbols;
1092 key = args + numArgsPushed + 1;
1093 for (i=0; i<numKeyArgsPushed; ++i, key+=2) {
1094 name = name0;
1095 for (j=0; j<methraw->posargs; ++j, ++name) {
1096 if (*name == slotRawSymbol(key)) {
1097 slotCopy(&vars[j+1],&key[1]);
1098 goto found1;
1101 if (gKeywordError) {
1102 post("WARNING: keyword arg '%s' not found in call to function.\n",
1103 slotRawSymbol(key)->name);
1105 found1: ;
1109 homeContext = slotRawFrame(&frame->homeContext);
1110 if (homeContext) {
1111 PyrMethodRaw *methraw;
1112 g->method = slotRawMethod(&homeContext->method);
1113 methraw = METHRAW(g->method);
1114 slotCopy(&g->receiver,&homeContext->vars[0]);
1115 } else {
1116 slotCopy(&g->receiver,&g->process->interpreter);
1118 return errNone;
1121 bool identDict_lookupNonNil(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result);
1123 int blockValueEnvir(struct VMGlobals *g, int numArgsPushed)
1125 PyrSlot *args;
1126 PyrSlot *vars;
1127 PyrFrame *frame;
1128 PyrSlot *pslot, *qslot;
1129 PyrSlot *rslot;
1130 PyrObject *proto;
1131 int i, m, mmax, numtemps;
1132 PyrBlock *block;
1133 PyrFrame *context;
1134 PyrFrame *caller;
1135 PyrFrame *homeContext;
1136 PyrClosure *closure;
1137 PyrMethodRaw *methraw;
1138 PyrSlot *curEnvirSlot;
1140 #if TAILCALLOPTIMIZE
1141 int tailCall = g->tailCall;
1142 if (tailCall) {
1143 if (tailCall == 1) {
1144 returnFromMethod(g);
1145 } else {
1146 returnFromBlock(g);
1149 #endif
1151 g->execMethod = 50;
1153 args = g->sp - numArgsPushed + 1;
1155 numArgsPushed -- ;
1156 g->numpop = 0;
1158 closure = (PyrClosure*)slotRawObject(args);
1159 block = slotRawBlock(&closure->block);
1160 context = slotRawFrame(&closure->context);
1162 proto = slotRawObject(&block->prototypeFrame);
1163 methraw = METHRAW(block);
1164 numtemps = methraw->numtemps;
1165 caller = g->frame;
1167 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
1168 vars = frame->vars - 1;
1169 frame->classptr = class_frame;
1170 frame->size = FRAMESIZE + numtemps;
1171 SetObject(&frame->method, block);
1172 slotCopy(&frame->homeContext,&context->homeContext);
1173 slotCopy(&frame->context,&closure->context);
1175 if (caller) {
1176 SetPtr(&caller->ip, g->ip);
1177 SetObject(&frame->caller, g->frame);
1178 } else {
1179 SetInt(&frame->caller, 0);
1181 SetPtr(&frame->ip, 0);
1184 g->sp = args - 1;
1185 g->ip = slotRawInt8Array(&block->code)->b - 1;
1186 g->frame = frame;
1187 g->block = block;
1189 if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
1190 /* push all args to frame */
1191 qslot = args;
1192 pslot = vars;
1194 for (m=0; m<numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1196 /* push default arg values */
1197 pslot = vars + numArgsPushed;
1198 qslot = proto->slots + numArgsPushed - 1;
1199 for (m=0; m<numtemps - numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1201 // replace defaults with environment variables
1202 curEnvirSlot = &g->classvars->slots[1]; // currentEnvironment is the second class var.
1204 if (isKindOfSlot(curEnvirSlot, s_identitydictionary->u.classobj)) {
1205 PyrSymbol **argNames;
1206 argNames = slotRawSymbolArray(&block->argNames)->symbols;
1207 for (m=numArgsPushed; m<methraw->numargs; ++m) {
1208 // replace the args with values from the environment if they exist
1209 PyrSlot keyslot;
1210 SetSymbol(&keyslot, argNames[m]);
1211 identDict_lookupNonNil(slotRawObject(curEnvirSlot), &keyslot, calcHash(&keyslot), vars+m+1);
1214 } else if (methraw->varargs) {
1215 PyrObject *list;
1216 PyrSlot *lslot;
1218 /* push all normal args to frame */
1219 qslot = args;
1220 pslot = vars;
1221 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1223 /* push list */
1224 i = numArgsPushed - methraw->numargs;
1225 list = newPyrArray(g->gc, i, 0, false);
1226 list->size = i;
1228 rslot = pslot+1;
1229 SetObject(rslot, list);
1230 //SetObject(vars + methraw->numargs + 1, list);
1232 /* put extra args into list */
1233 lslot = list->slots - 1;
1234 // fixed and raw sizes are zero
1235 for (m=0; m<i; ++m) slotCopy(++lslot, ++qslot);
1237 if (methraw->numvars) {
1238 /* push default keyword and var values */
1239 pslot = vars + methraw->numargs + 1;
1240 qslot = proto->slots + methraw->numargs;
1241 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1243 } else {
1244 if (methraw->numargs) {
1245 /* push all args to frame */
1246 qslot = args;
1247 pslot = vars;
1248 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1250 if (methraw->numvars) {
1251 /* push default keyword and var values */
1252 pslot = vars + methraw->numargs;
1253 qslot = proto->slots + methraw->numargs - 1;
1254 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1258 homeContext = slotRawFrame(&frame->homeContext);
1259 if (homeContext) {
1260 PyrMethodRaw *methraw;
1261 g->method = slotRawMethod(&homeContext->method);
1262 methraw = METHRAW(g->method);
1263 slotCopy(&g->receiver,&homeContext->vars[0]);
1264 } else {
1265 slotCopy(&g->receiver,&g->process->interpreter);
1267 return errNone;
1270 int blockValueEnvirWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed);
1271 int blockValueEnvirWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed)
1273 PyrSlot *args;
1274 PyrSlot *vars;
1275 PyrFrame *frame;
1276 PyrSlot *pslot, *qslot;
1277 PyrSlot *rslot;
1278 PyrObject *proto;
1279 int i, j, m, mmax, numtemps, numArgsPushed;
1280 PyrBlock *block;
1281 PyrFrame *context;
1282 PyrFrame *caller;
1283 PyrFrame *homeContext;
1284 PyrClosure *closure;
1285 PyrMethodRaw *methraw;
1286 PyrSlot *curEnvirSlot;
1288 #if TAILCALLOPTIMIZE
1289 int tailCall = g->tailCall;
1290 if (tailCall) {
1291 if (tailCall == 1) {
1292 returnFromMethod(g);
1293 } else {
1294 returnFromBlock(g);
1297 #endif
1299 g->execMethod = 60;
1301 args = g->sp - allArgsPushed + 1;
1303 allArgsPushed -- ;
1304 g->numpop = 0;
1306 closure = (PyrClosure*)slotRawObject(args);
1307 block = slotRawBlock(&closure->block);
1308 context = slotRawFrame(&closure->context);
1310 proto = slotRawObject(&block->prototypeFrame);
1311 methraw = METHRAW(block);
1312 numtemps = methraw->numtemps;
1313 caller = g->frame;
1314 numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1);
1316 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
1317 vars = frame->vars - 1;
1318 frame->classptr = class_frame;
1319 frame->size = FRAMESIZE + numtemps;
1320 SetObject(&frame->method, block);
1321 slotCopy(&frame->homeContext,&context->homeContext);
1322 slotCopy(&frame->context,&closure->context);
1324 if (caller) {
1325 SetPtr(&caller->ip, g->ip);
1326 SetObject(&frame->caller, g->frame);
1327 } else {
1328 SetInt(&frame->caller, 0);
1330 SetPtr(&frame->ip, 0);
1333 g->sp = args - 1;
1334 g->ip = slotRawInt8Array(&block->code)->b - 1;
1335 g->frame = frame;
1336 g->block = block;
1338 if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
1339 /* push all args to frame */
1340 qslot = args;
1341 pslot = vars;
1343 for (m=0; m<numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1345 /* push default arg values */
1346 pslot = vars + numArgsPushed;
1347 qslot = proto->slots + numArgsPushed - 1;
1348 for (m=0; m<numtemps - numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1350 // replace defaults with environment variables
1351 curEnvirSlot = &g->classvars->slots[1]; // currentEnvironment is the second class var.
1353 if (isKindOfSlot(curEnvirSlot, s_identitydictionary->u.classobj)) {
1354 PyrSymbol **argNames;
1355 argNames = slotRawSymbolArray(&block->argNames)->symbols;
1356 for (m=numArgsPushed; m<methraw->numargs; ++m) {
1357 // replace the args with values from the environment if they exist
1358 PyrSlot keyslot;
1359 SetSymbol(&keyslot, argNames[m]);
1360 identDict_lookupNonNil(slotRawObject(curEnvirSlot), &keyslot, calcHash(&keyslot), vars+m+1);
1365 } else if (methraw->varargs) {
1366 PyrObject *list;
1367 PyrSlot *lslot;
1369 /* push all normal args to frame */
1370 qslot = args;
1371 pslot = vars;
1372 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1374 /* push list */
1375 i = numArgsPushed - methraw->numargs;
1376 list = newPyrArray(g->gc, i, 0, false);
1377 list->size = i;
1379 rslot = pslot+1;
1380 SetObject(rslot, list);
1381 //SetObject(vars + methraw->numargs + 1, list);
1383 /* put extra args into list */
1384 lslot = list->slots - 1;
1385 // fixed and raw sizes are zero
1386 //lend = lslot + i;
1387 //while (lslot < lend) slotCopy(++lslot, ++qslot);
1388 for (m=0; m<i; ++m) slotCopy(++lslot, ++qslot);
1390 if (methraw->numvars) {
1391 /* push default keyword and var values */
1392 pslot = vars + methraw->numargs + 1;
1393 qslot = proto->slots + methraw->numargs;
1394 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1396 } else {
1397 if (methraw->numargs) {
1398 /* push all args to frame */
1399 qslot = args;
1400 pslot = vars;
1401 //pend = pslot + methraw->numargs;
1402 //while (pslot < pend) slotCopy(++pslot, ++qslot);
1403 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1405 if (methraw->numvars) {
1406 /* push default keyword and var values */
1407 pslot = vars + methraw->numargs;
1408 qslot = proto->slots + methraw->numargs - 1;
1409 //pend = pslot + methraw->numvars;
1410 //while (pslot<pend) slotCopy(++pslot, ++qslot);
1411 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1414 // do keyword lookup:
1415 if (numKeyArgsPushed && methraw->posargs) {
1416 PyrSymbol **name0, **name;
1417 PyrSlot *key;
1418 name0 = slotRawSymbolArray(&block->argNames)->symbols;
1419 key = args + numArgsPushed + 1;
1420 for (i=0; i<numKeyArgsPushed; ++i, key+=2) {
1421 name = name0;
1422 for (j=0; j<methraw->posargs; ++j, ++name) {
1423 if (*name == slotRawSymbol(key)) {
1424 slotCopy(&vars[j+1],&key[1]);
1425 goto found1;
1428 if (gKeywordError) {
1429 post("WARNING: keyword arg '%s' not found in call to function.\n",
1430 slotRawSymbol(key)->name);
1432 found1: ;
1436 homeContext = slotRawFrame(&frame->homeContext);
1437 if (homeContext) {
1438 PyrMethodRaw *methraw;
1439 g->method = slotRawMethod(&homeContext->method);
1440 methraw = METHRAW(g->method);
1441 slotCopy(&g->receiver,&homeContext->vars[0]);
1442 } else {
1443 slotCopy(&g->receiver,&g->process->interpreter);
1445 return errNone;
1449 int objectPerform(struct VMGlobals *g, int numArgsPushed)
1451 PyrSlot *recvrSlot, *selSlot, *listSlot;
1452 PyrSlot *pslot, *qslot;
1453 PyrSymbol *selector;
1454 int m, mmax;
1456 recvrSlot = g->sp - numArgsPushed + 1;
1457 selSlot = recvrSlot + 1;
1458 if (IsSym(selSlot)) {
1459 selector = slotRawSymbol(selSlot);
1460 // move args down one to fill selector's position
1461 pslot = selSlot - 1;
1462 qslot = selSlot;
1463 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(++pslot, ++qslot);
1464 g->sp -- ;
1465 numArgsPushed -- ;
1466 // now the stack looks just like it would for a normal message send
1467 } else if (IsObj(selSlot)) {
1468 listSlot = selSlot;
1469 if (slotRawObject(listSlot)->classptr == class_list) {
1470 listSlot = slotRawObject(listSlot)->slots;
1472 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1473 goto badselector;
1475 PyrObject *array = slotRawObject(listSlot);
1476 if (array->size < 1) {
1477 error("Array must have a selector.\n");
1478 return errFailed;
1480 selSlot = array->slots;
1481 selector = slotRawSymbol(selSlot);
1483 if (numArgsPushed>2) {
1484 qslot = recvrSlot + numArgsPushed;
1485 pslot = recvrSlot + numArgsPushed + array->size - 2;
1486 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(--pslot, --qslot);
1489 pslot = recvrSlot;
1490 qslot = selSlot;
1491 for (m=0,mmax=array->size-1; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1493 g->sp += array->size - 2;
1494 numArgsPushed += array->size - 2;
1495 // now the stack looks just like it would for a normal message send
1497 } else {
1498 badselector:
1499 error("perform selector not a Symbol or Array.\n");
1500 dumpObjectSlot(selSlot);
1501 return errWrongType;
1504 sendMessage(g, selector, numArgsPushed);
1505 g->numpop = 0;
1506 return errNone;
1509 int objectPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed);
1510 int objectPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed)
1512 PyrSlot *recvrSlot, *selSlot, *listSlot;
1513 PyrSlot *pslot, *qslot;
1514 PyrSymbol *selector;
1515 int m, mmax;
1517 recvrSlot = g->sp - numArgsPushed + 1;
1518 selSlot = recvrSlot + 1;
1519 if (IsSym(selSlot)) {
1520 selector = slotRawSymbol(selSlot);
1521 // move args down one to fill selector's position
1522 pslot = selSlot - 1;
1523 qslot = selSlot;
1524 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(++pslot, ++qslot);
1525 g->sp -- ;
1526 numArgsPushed -- ;
1527 // now the stack looks just like it would for a normal message send
1528 } else if (IsObj(selSlot)) {
1529 listSlot = selSlot;
1530 if (slotRawObject(listSlot)->classptr == class_list) {
1531 listSlot = slotRawObject(listSlot)->slots;
1533 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1534 goto badselector;
1536 PyrObject *array = slotRawObject(listSlot);
1537 if (array->size < 1) {
1538 error("Array must have a selector.\n");
1539 return errFailed;
1541 selSlot = array->slots;
1542 selector = slotRawSymbol(selSlot);
1544 if (numArgsPushed>2) {
1545 qslot = recvrSlot + numArgsPushed;
1546 pslot = recvrSlot + numArgsPushed + array->size - 2;
1547 for (m=0; m<numArgsPushed - 2; ++m) *--pslot = *--qslot;
1550 pslot = recvrSlot;
1551 qslot = selSlot;
1552 for (m=0,mmax=array->size-1; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1554 g->sp += array->size - 2;
1555 numArgsPushed += array->size - 2;
1556 // now the stack looks just like it would for a normal message send
1558 } else {
1559 badselector:
1560 error("perform selector not a Symbol or Array.\n");
1561 dumpObjectSlot(selSlot);
1562 return errWrongType;
1565 sendMessageWithKeys(g, selector, numArgsPushed, numKeyArgsPushed);
1566 g->numpop = 0;
1567 return errNone;
1571 int objectPerformList(struct VMGlobals *g, int numArgsPushed)
1573 PyrSlot *recvrSlot, *selSlot, *listSlot;
1574 PyrSlot *pslot, *qslot;
1575 PyrSymbol *selector;
1576 int m, mmax, numargslots;
1577 PyrObject *array;
1580 recvrSlot = g->sp - numArgsPushed + 1;
1581 selSlot = recvrSlot + 1;
1582 listSlot = g->sp;
1583 numargslots = numArgsPushed - 3;
1584 if (NotSym(selSlot)) {
1585 error("Selector not a Symbol :\n");
1586 return errWrongType;
1588 selector = slotRawSymbol(selSlot);
1590 if (NotObj(listSlot)) {
1591 return objectPerform(g, numArgsPushed);
1593 if (slotRawObject(listSlot)->classptr == class_array) {
1594 doarray:
1595 array = slotRawObject(listSlot);
1597 PyrObject *stack = g->gc->Stack();
1598 int stackDepth = g->sp - stack->slots + 1;
1599 int stackSize = ARRAYMAXINDEXSIZE(stack);
1600 int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations.
1601 if (stackNeeded > stackSize) {
1602 reallocStack(g, stackNeeded, stackDepth);
1603 recvrSlot = g->sp - numArgsPushed + 1;
1604 selSlot = recvrSlot + 1;
1607 pslot = recvrSlot;
1608 if (numargslots>0) {
1609 qslot = selSlot;
1610 for (m=0; m<numargslots; ++m) slotCopy(++pslot, ++qslot);
1611 } else numargslots = 0;
1612 qslot = array->slots - 1;
1613 for (m=0,mmax=array->size; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1614 } else if (slotRawObject(listSlot)->classptr == class_list) {
1615 listSlot = slotRawObject(listSlot)->slots;
1616 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1617 error("List array not an Array.\n");
1618 dumpObjectSlot(listSlot);
1619 return errWrongType;
1621 goto doarray;
1622 } else {
1623 return objectPerform(g, numArgsPushed);
1625 g->sp += array->size - 2;
1626 numArgsPushed = numargslots + array->size + 1;
1627 // now the stack looks just like it would for a normal message send
1629 sendMessage(g, selector, numArgsPushed);
1630 g->numpop = 0;
1632 return errNone;
1636 int objectSuperPerform(struct VMGlobals *g, int numArgsPushed)
1638 PyrSlot *recvrSlot, *selSlot, *listSlot;
1639 PyrSlot *pslot, *qslot;
1640 PyrSymbol *selector;
1641 int m, mmax;
1643 recvrSlot = g->sp - numArgsPushed + 1;
1645 PyrClass* classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj;
1646 if (!isKindOfSlot(recvrSlot, classobj)) {
1647 error("superPerform must be called with 'this' as the receiver.\n");
1648 return errFailed;
1651 selSlot = recvrSlot + 1;
1652 if (IsSym(selSlot)) {
1653 selector = slotRawSymbol(selSlot);
1654 // move args down one to fill selector's position
1655 pslot = selSlot - 1;
1656 qslot = selSlot;
1657 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(++pslot, ++qslot);
1658 g->sp -- ;
1659 numArgsPushed -- ;
1660 // now the stack looks just like it would for a normal message send
1661 } else if (IsObj(selSlot)) {
1662 listSlot = selSlot;
1663 if (slotRawObject(listSlot)->classptr == class_list) {
1664 listSlot = slotRawObject(listSlot)->slots;
1666 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1667 goto badselector;
1669 PyrObject *array = slotRawObject(listSlot);
1670 if (array->size < 1) {
1671 error("Array must have a selector.\n");
1672 return errFailed;
1674 selSlot = array->slots;
1675 selector = slotRawSymbol(selSlot);
1677 if (numArgsPushed>2) {
1678 qslot = recvrSlot + numArgsPushed;
1679 pslot = recvrSlot + numArgsPushed + array->size - 2;
1680 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(--pslot, --qslot);
1683 pslot = recvrSlot;
1684 qslot = selSlot;
1685 for (m=0,mmax=array->size-1; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1687 g->sp += array->size - 2;
1688 numArgsPushed += array->size - 2;
1689 // now the stack looks just like it would for a normal message send
1691 } else {
1692 badselector:
1693 error("perform selector not a Symbol or Array.\n");
1694 dumpObjectSlot(selSlot);
1695 return errWrongType;
1698 sendSuperMessage(g, selector, numArgsPushed);
1699 g->numpop = 0;
1700 return errNone;
1703 int objectSuperPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed);
1704 int objectSuperPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed)
1706 PyrSlot *recvrSlot, *selSlot, *listSlot;
1707 PyrSlot *pslot, *qslot;
1708 PyrSymbol *selector;
1709 int m, mmax;
1711 recvrSlot = g->sp - numArgsPushed + 1;
1713 PyrClass* classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj;
1714 if (!isKindOfSlot(recvrSlot, classobj)) {
1715 error("superPerform must be called with 'this' as the receiver.\n");
1716 return errFailed;
1719 selSlot = recvrSlot + 1;
1720 if (IsSym(selSlot)) {
1721 selector = slotRawSymbol(selSlot);
1722 // move args down one to fill selector's position
1723 pslot = selSlot - 1;
1724 qslot = selSlot;
1725 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(++pslot, ++qslot);
1726 g->sp -- ;
1727 numArgsPushed -- ;
1728 // now the stack looks just like it would for a normal message send
1729 } else if (IsObj(selSlot)) {
1730 listSlot = selSlot;
1731 if (slotRawObject(listSlot)->classptr == class_list) {
1732 listSlot = slotRawObject(listSlot)->slots;
1734 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1735 goto badselector;
1737 PyrObject *array = slotRawObject(listSlot);
1738 if (array->size < 1) {
1739 error("Array must have a selector.\n");
1740 return errFailed;
1742 selSlot = array->slots;
1743 selector = slotRawSymbol(selSlot);
1745 if (numArgsPushed>2) {
1746 qslot = recvrSlot + numArgsPushed;
1747 pslot = recvrSlot + numArgsPushed + array->size - 2;
1748 for (m=0; m<numArgsPushed - 2; ++m) *--pslot = *--qslot;
1751 pslot = recvrSlot;
1752 qslot = selSlot;
1753 for (m=0,mmax=array->size-1; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1755 g->sp += array->size - 2;
1756 numArgsPushed += array->size - 2;
1757 // now the stack looks just like it would for a normal message send
1759 } else {
1760 badselector:
1761 error("perform selector not a Symbol or Array.\n");
1762 dumpObjectSlot(selSlot);
1763 return errWrongType;
1766 sendSuperMessageWithKeys(g, selector, numArgsPushed, numKeyArgsPushed);
1767 g->numpop = 0;
1768 return errNone;
1772 int objectSuperPerformList(struct VMGlobals *g, int numArgsPushed)
1774 PyrSlot *recvrSlot, *selSlot, *listSlot;
1775 PyrSlot *pslot, *qslot;
1776 PyrSymbol *selector;
1777 int m, mmax, numargslots;
1778 PyrObject *array;
1780 recvrSlot = g->sp - numArgsPushed + 1;
1781 selSlot = recvrSlot + 1;
1782 listSlot = g->sp;
1783 numargslots = numArgsPushed - 3;
1784 if (NotSym(selSlot)) {
1785 error("Selector not a Symbol :\n");
1786 return errWrongType;
1788 selector = slotRawSymbol(selSlot);
1789 if (NotObj(listSlot)) {
1790 return objectPerform(g, numArgsPushed);
1792 if (slotRawObject(listSlot)->classptr == class_array) {
1793 doarray:
1794 pslot = recvrSlot;
1795 if (numargslots>0) {
1796 qslot = selSlot;
1797 for (m=0; m<numargslots; ++m) slotCopy(++pslot, ++qslot);
1798 } else numargslots = 0;
1799 array = slotRawObject(listSlot);
1800 qslot = array->slots - 1;
1801 for (m=0,mmax=array->size; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1802 } else if (slotRawObject(listSlot)->classptr == class_list) {
1803 listSlot = slotRawObject(listSlot)->slots;
1804 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1805 error("List array not an Array.\n");
1806 dumpObjectSlot(listSlot);
1807 return errWrongType;
1809 goto doarray;
1810 } else {
1811 return objectSuperPerform(g, numArgsPushed);
1813 g->sp += array->size - 2;
1814 numArgsPushed = numargslots + array->size + 1;
1815 // now the stack looks just like it would for a normal message send
1817 sendSuperMessage(g, selector, numArgsPushed);
1818 g->numpop = 0;
1819 return errNone;
1825 int objectPerformSelList(struct VMGlobals *g, int numArgsPushed)
1827 PyrSlot *recvrSlot, *selSlot, *listSlot;
1828 PyrSlot *pslot, *qslot;
1829 PyrSymbol *selector;
1830 int m, mmax;
1831 PyrObject *array;
1833 recvrSlot = g->sp - 1;
1834 listSlot = g->sp;
1836 if (NotObj(listSlot)) {
1837 error("Expected Array or List.. Got :\n");
1838 dumpObjectSlot(listSlot);
1839 return errWrongType;
1841 if (slotRawObject(listSlot)->classptr == class_array) {
1842 doarray:
1843 array = slotRawObject(listSlot);
1845 selSlot = array->slots;
1846 if (NotSym(selSlot)) {
1847 error("Selector not a Symbol :\n");
1848 return errWrongType;
1850 selector = slotRawSymbol(selSlot);
1852 pslot = recvrSlot;
1853 qslot = selSlot;
1854 for (m=0,mmax=array->size-1; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1855 } else if (slotRawObject(listSlot)->classptr == class_list) {
1856 listSlot = slotRawObject(listSlot)->slots;
1857 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1858 error("List array not an Array.\n");
1859 dumpObjectSlot(listSlot);
1860 return errWrongType;
1862 goto doarray;
1863 } else {
1864 error("Expected Array or List.. Got :\n");
1865 dumpObjectSlot(listSlot);
1866 return errWrongType;
1868 g->sp += array->size - 2;
1869 numArgsPushed = array->size;
1870 // now the stack looks just like it would for a normal message send
1872 sendMessage(g, selector, numArgsPushed);
1873 g->numpop = 0;
1874 return errNone;
1878 int arrayPerformMsg(struct VMGlobals *g, int numArgsPushed);
1879 int arrayPerformMsg(struct VMGlobals *g, int numArgsPushed)
1881 PyrSlot *recvrSlot, *selSlot, *arraySlot;
1882 PyrSlot *pslot, *qslot;
1883 PyrSymbol *selector;
1884 int m, mmax, numargslots;
1885 PyrObject *array;
1887 arraySlot = g->sp - numArgsPushed + 1;
1888 array = slotRawObject(arraySlot);
1889 if (array->size < 2) {
1890 error("Array must contain a receiver and a selector.\n");
1891 return errFailed;
1893 recvrSlot = array->slots;
1894 selSlot = recvrSlot + 1;
1895 numargslots = numArgsPushed - 1;
1896 if (NotSym(selSlot)) {
1897 error("Selector not a Symbol :\n");
1898 return errWrongType;
1901 selector = slotRawSymbol(selSlot);
1903 slotCopy(arraySlot,recvrSlot);
1905 if (numargslots>0) {
1906 qslot = arraySlot + numargslots + 1;
1907 pslot = arraySlot + numargslots + array->size - 1;
1908 for (m=0; m<numargslots; ++m) slotCopy(--pslot, --qslot);
1909 } else numargslots = 0;
1911 pslot = arraySlot;
1912 qslot = selSlot;
1913 for (m=0,mmax=array->size-2; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1915 g->sp += array->size - 2;
1916 numArgsPushed = numargslots + array->size - 1;
1918 // now the stack looks just like it would for a normal message send
1920 sendMessage(g, selector, numArgsPushed);
1921 g->numpop = 0;
1922 return errNone;
1925 int objectDump(struct VMGlobals *g, int numArgsPushed)
1927 PyrSlot *a;
1929 a = g->sp;
1930 dumpObjectSlot(a);
1931 return errNone;
1935 int prTotalFree(struct VMGlobals *g, int numArgsPushed);
1936 int prTotalFree(struct VMGlobals *g, int numArgsPushed)
1938 PyrSlot *a = g->sp;
1939 SetInt(a, g->allocPool->TotalFree());
1940 return errNone;
1943 int prLargestFreeBlock(struct VMGlobals *g, int numArgsPushed);
1944 int prLargestFreeBlock(struct VMGlobals *g, int numArgsPushed)
1946 PyrSlot *a = g->sp;
1947 SetInt(a, g->allocPool->LargestFreeChunk());
1948 return errNone;
1951 int dumpGCinfo(struct VMGlobals *g, int numArgsPushed);
1952 int dumpGCinfo(struct VMGlobals *g, int numArgsPushed)
1954 g->gc->DumpInfo();
1955 return errNone;
1958 int dumpGCdumpGrey(struct VMGlobals *g, int numArgsPushed);
1959 int dumpGCdumpGrey(struct VMGlobals *g, int numArgsPushed)
1961 g->gc->DumpGrey();
1962 return errNone;
1965 int dumpGCdumpSet(struct VMGlobals *g, int numArgsPushed);
1966 int dumpGCdumpSet(struct VMGlobals *g, int numArgsPushed)
1968 PyrSlot *b = g->sp;
1969 int set;
1970 int err = slotIntVal(b, &set);
1971 if (err) return err;
1973 g->gc->DumpSet(set);
1974 return errNone;
1977 int prGCSanity(struct VMGlobals *g, int numArgsPushed);
1978 int prGCSanity(struct VMGlobals *g, int numArgsPushed)
1980 g->gc->SanityCheck();
1981 return errNone;
1984 #if GCDEBUG
1985 int prTraceAllPathsTo(struct VMGlobals *g, int numArgsPushed);
1986 int prTraceAllPathsTo(struct VMGlobals *g, int numArgsPushed)
1988 PyrSlot *a = g->sp;
1989 g->gc->TracePathsTo(slotRawObject(a), false);
1990 return errNone;
1993 int prTraceAnyPathsTo(struct VMGlobals *g, int numArgsPushed);
1994 int prTraceAnyPathsTo(struct VMGlobals *g, int numArgsPushed)
1996 PyrSlot *a = g->sp;
1997 g->gc->TracePathsTo(slotRawObject(a), true);
1998 return errNone;
2001 int prTraceAnyPathToAllInstancesOf(struct VMGlobals *g, int numArgsPushed);
2002 int prTraceAnyPathToAllInstancesOf(struct VMGlobals *g, int numArgsPushed)
2004 PyrSlot *a = g->sp;
2005 g->gc->TraceAnyPathToAllInstancesOf(slotRawClass(a)->name.us);
2006 return errNone;
2008 #endif
2010 extern PyrClass *gClassList;
2012 int prAllClasses(struct VMGlobals *g, int numArgsPushed)
2014 PyrSlot *a;
2015 PyrClass *classobj;
2016 PyrObject *array;
2017 int i;
2019 a = g->sp;
2021 array = newPyrArray(g->gc, gNumClasses, 0, true);
2022 classobj = gClassList;
2023 for (i=0; classobj; ++i) {
2024 SetObject(array->slots + i, classobj);
2025 classobj = slotRawClass(&classobj->nextclass);
2027 array->size = gNumClasses;
2028 SetObject(a, array);
2029 return errNone;
2032 int prPostClassTree(struct VMGlobals *g, int numArgsPushed)
2034 PyrSlot *a;
2036 a = g->sp;
2037 postClassTree(slotRawClass(a), 0);
2038 return errNone;
2041 int prDumpBackTrace(struct VMGlobals *g, int numArgsPushed)
2043 PyrSlot *a;
2045 a = g->sp;
2046 DumpBackTrace(g);
2047 return errNone;
2050 /* the DebugFrameConstructor uses a work queue in order to avoid recursions, which could lead to stack overflows */
2051 struct DebugFrameConstructor
2053 void makeDebugFrame (VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot)
2055 workQueue.push_back(std::make_pair(frame, outSlot));
2056 run_queue(g);
2059 private:
2060 void run_queue(VMGlobals *g)
2062 while (!workQueue.empty()) {
2063 WorkQueueItem work = workQueue.back();
2064 workQueue.pop_back();
2065 fillDebugFrame(g, work.first, work.second);
2069 void fillDebugFrame(VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot)
2071 PyrMethod *meth = slotRawMethod(&frame->method);
2072 PyrMethodRaw * methraw = METHRAW(meth);
2074 PyrObject* debugFrameObj = instantiateObject(g->gc, getsym("DebugFrame")->u.classobj, 0, false, true);
2075 SetObject(outSlot, debugFrameObj);
2077 SetObject(debugFrameObj->slots + 0, meth);
2078 SetPtr(debugFrameObj->slots + 5, meth);
2080 int numargs = methraw->numargs;
2081 int numvars = methraw->numvars;
2082 if (numargs) {
2083 PyrObject* argArray = (PyrObject*)newPyrArray(g->gc, numargs, 0, false);
2084 SetObject(debugFrameObj->slots + 1, argArray);
2085 for (int i=0; i<numargs; ++i)
2086 slotCopy(&argArray->slots[i], &frame->vars[i]);
2088 argArray->size = numargs;
2089 } else
2090 SetNil(debugFrameObj->slots + 1);
2092 if (numvars) {
2093 PyrObject* varArray = (PyrObject*)newPyrArray(g->gc, numvars, 0, false);
2094 SetObject(debugFrameObj->slots + 2, varArray);
2095 for (int i=0, j=numargs; i<numvars; ++i,++j)
2096 slotCopy(&varArray->slots[i], &frame->vars[j]);
2098 varArray->size = numvars;
2099 } else
2100 SetNil(debugFrameObj->slots + 2);
2102 if (slotRawFrame(&frame->caller)) {
2103 WorkQueueItem newWork = std::make_pair(slotRawFrame(&frame->caller), debugFrameObj->slots + 3);
2104 workQueue.push_back(newWork);
2105 } else
2106 SetNil(debugFrameObj->slots + 3);
2108 if (IsObj(&frame->context) && slotRawFrame(&frame->context) == frame)
2109 SetObject(debugFrameObj->slots + 4, debugFrameObj);
2110 else if (NotNil(&frame->context)) {
2111 WorkQueueItem newWork = std::make_pair(slotRawFrame(&frame->context), debugFrameObj->slots + 4);
2112 workQueue.push_back(newWork);
2113 } else
2114 SetNil(debugFrameObj->slots + 4);
2117 typedef std::pair<PyrFrame*, PyrSlot*> WorkQueueItem;
2118 typedef std::vector<WorkQueueItem> WorkQueueType;
2119 WorkQueueType workQueue;
2122 static void MakeDebugFrame(VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot)
2124 DebugFrameConstructor constructor;
2125 constructor.makeDebugFrame(g, frame, outSlot);
2128 int prGetBackTrace(VMGlobals *g, int numArgsPushed);
2129 int prGetBackTrace(VMGlobals *g, int numArgsPushed)
2131 PyrSlot *a;
2133 a = g->sp;
2134 MakeDebugFrame(g, g->frame, a);
2136 return errNone;
2139 int prObjectShallowCopy(struct VMGlobals *g, int numArgsPushed)
2141 PyrSlot *a;
2143 a = g->sp;
2144 switch (GetTag(a)) {
2145 case tagObj :
2146 SetRaw(a, copyObject(g->gc, slotRawObject(a), true));
2147 break;
2148 // the default case is to leave the argument unchanged on the stack
2150 return errNone;
2153 int prObjectCopyImmutable(struct VMGlobals *g, int numArgsPushed);
2154 int prObjectCopyImmutable(struct VMGlobals *g, int numArgsPushed)
2156 PyrSlot *a;
2158 a = g->sp;
2159 switch (GetTag(a)) {
2160 case tagObj :
2161 if (slotRawObject(a)->obj_flags & obj_immutable) {
2162 SetRaw(a, copyObject(g->gc, slotRawObject(a), true));
2164 break;
2166 return errNone;
2169 int prObjectIsMutable(struct VMGlobals *g, int numArgsPushed);
2170 int prObjectIsMutable(struct VMGlobals *g, int numArgsPushed)
2172 PyrSlot *a;
2174 a = g->sp;
2175 if (IsObj(a)) {
2176 if (slotRawObject(a)->obj_flags & obj_immutable) {
2177 SetFalse(a);
2178 } else {
2179 SetTrue(a);
2181 } else {
2182 SetFalse(a);
2184 return errNone;
2187 int prObjectIsPermanent(struct VMGlobals *g, int numArgsPushed);
2188 int prObjectIsPermanent(struct VMGlobals *g, int numArgsPushed)
2190 PyrSlot *a;
2192 a = g->sp;
2193 if (IsObj(a)) {
2194 if (slotRawObject(a)->gc_color == obj_permanent) {
2195 SetTrue(a);
2196 } else {
2197 SetFalse(a);
2199 } else {
2200 SetTrue(a);
2202 return errNone;
2207 int prDeepFreeze(struct VMGlobals *g, int numArgsPushed);
2208 int prDeepFreeze(struct VMGlobals *g, int numArgsPushed)
2210 PyrSlot *a;
2212 a = g->sp;
2213 PyrDeepFreezer freezer(g);
2214 int err = freezer.doDeepFreeze(a);
2215 return err;
2219 int prDeepCopy(struct VMGlobals *g, int numArgsPushed);
2220 int prDeepCopy(struct VMGlobals *g, int numArgsPushed)
2222 PyrSlot *a;
2224 a = g->sp;
2225 PyrDeepCopier copier(g);
2226 int err = copier.doDeepCopy(a);
2227 return err;
2233 bool IsSimpleLiteralSlot(PyrSlot* slot);
2234 bool IsSimpleLiteralSlot(PyrSlot* slot)
2236 switch (GetTag(slot)) {
2237 case tagObj : return slotRawObject(slot)->IsPermanent();
2238 case tagInt : return true;
2239 case tagSym : return true;
2240 case tagChar : return true;
2241 case tagNil : return true;
2242 case tagFalse : return true;
2243 case tagTrue : return true;
2244 case tagPtr : return false;
2245 default : return true;
2251 int prObjectCopyRange(struct VMGlobals *g, int numArgsPushed)
2253 PyrSlot *a, *b, *c;
2255 a = g->sp - 2;
2256 b = g->sp - 1;
2257 c = g->sp;
2259 if (NotObj(a)) return errWrongType;
2260 if (NotInt(b)) return errWrongType;
2261 if (NotInt(c)) return errWrongType;
2262 SetRaw(a, copyObjectRange(g->gc, slotRawObject(a), slotRawInt(b), slotRawInt(c), true));
2264 return errNone;
2268 int prObjectCopySeries(struct VMGlobals *g, int numArgsPushed)
2270 PyrSlot *a, *b, *c, *d;
2272 a = g->sp - 3;
2273 b = g->sp - 2;
2274 c = g->sp - 1;
2275 d = g->sp;
2277 PyrObject *inobj = slotRawObject(a);
2278 PyrObject *newobj;
2280 int size = inobj->size;
2281 int flags = ~(obj_immutable) & inobj->obj_flags;
2283 int first, second, last;
2285 if (IsInt(b)) first = slotRawInt(b);
2286 else if (IsNil(b)) first = 0;
2287 else return errWrongType;
2289 if (IsInt(d)) {
2290 last = slotRawInt(d);
2291 if (last < 0 && IsNil(b)) {
2292 zerolength:
2293 newobj = g->gc->New(0, flags, inobj->obj_format, true);
2294 newobj->size = 0;
2295 newobj->classptr = inobj->classptr;
2296 SetRaw(a, newobj);
2297 return errNone;
2299 } else if (IsNil(d)) {
2300 if (first >= size) goto zerolength;
2301 last = size - 1;
2302 } else return errWrongType;
2304 if (IsInt(c)) second = slotRawInt(c);
2305 else if (IsNil(c)) second = first < last ? first + 1 : first - 1;
2306 else return errWrongType;
2308 int step = second - first;
2310 int elemsize = gFormatElemSize[inobj->obj_format];
2311 int length;
2313 if (step > 0) {
2314 length = (last - first) / step + 1;
2315 } else if (step < 0) {
2316 length = (first - last) / -step + 1;
2317 } else return errFailed;
2319 int numbytes = length * elemsize;
2321 newobj = g->gc->New(numbytes, flags, inobj->obj_format, true);
2322 newobj->size = 0;
2323 newobj->classptr = inobj->classptr;
2325 for (int i=first, j=0; j<length; i+=step, ++j) {
2326 PyrSlot slot;
2327 if (i >= 0 && i < inobj->size) {
2328 getIndexedSlot(inobj, &slot, i);
2329 int err = putIndexedSlot(g, newobj, &slot, newobj->size++);
2330 if (err) return err;
2334 SetRaw(a, newobj);
2335 return errNone;
2338 void switchToThread(struct VMGlobals *g, struct PyrThread *newthread, int oldstate, int *numArgsPushed);
2340 int haltInterpreter(struct VMGlobals *g, int numArgsPushed)
2342 switchToThread(g, slotRawThread(&g->process->mainThread), tDone, &numArgsPushed);
2343 // return all the way out.
2344 //PyrSlot *bottom = g->gc->Stack()->slots;
2345 //slotCopy(bottom,g->sp);
2346 //g->sp = bottom; // ??!! pop everybody
2347 g->method = NULL;
2348 g->block = NULL;
2349 g->frame = NULL;
2350 SetNil(g->sp);
2351 longjmp(g->escapeInterpreter, 3);
2352 //hmm need to fix this to work only on main thread. //!!!
2353 //g->sp = g->gc->Stack()->slots - 1;
2355 return errReturn;
2359 int prCanCallOS(struct VMGlobals *g, int numArgsPushed);
2360 int prCanCallOS(struct VMGlobals *g, int numArgsPushed)
2362 PyrSlot *a = g->sp;
2364 SetBool(a, g->canCallOS);
2366 return errNone;
2369 extern bool gGenerateTailCallByteCodes;
2371 int prGetTailCallOptimize(struct VMGlobals *g, int numArgsPushed);
2372 int prGetTailCallOptimize(struct VMGlobals *g, int numArgsPushed)
2374 PyrSlot *a = g->sp;
2376 SetBool(a, gGenerateTailCallByteCodes);
2378 return errNone;
2381 int prSetTailCallOptimize(struct VMGlobals *g, int numArgsPushed);
2382 int prSetTailCallOptimize(struct VMGlobals *g, int numArgsPushed)
2384 //PyrSlot *a = g->sp - 1;
2386 #if TAILCALLOPTIMIZE
2387 PyrSlot *b = g->sp;
2388 if (IsTrue(b)) {
2389 gGenerateTailCallByteCodes = true;
2390 } else if (IsFalse(b)) {
2391 gGenerateTailCallByteCodes = false;
2392 } else return errWrongType;
2393 #endif
2395 return errNone;
2399 int prTraceOn(struct VMGlobals *g, int numArgsPushed);
2400 int prTraceOn(struct VMGlobals *g, int numArgsPushed)
2402 PyrSlot *a;
2404 a = g->sp;
2405 gTraceInterpreter = IsTrue(a);
2406 return errNone;
2409 int prKeywordError(struct VMGlobals *g, int numArgsPushed);
2410 int prKeywordError(struct VMGlobals *g, int numArgsPushed)
2412 PyrSlot *a;
2414 a = g->sp;
2415 gKeywordError = IsTrue(a);
2416 return errNone;
2419 int prFunDef_NumArgs(struct VMGlobals *g, int numArgsPushed);
2420 int prFunDef_NumArgs(struct VMGlobals *g, int numArgsPushed)
2422 PyrSlot *a;
2423 PyrMethodRaw *methraw;
2425 a = g->sp;
2426 methraw = METHRAW(slotRawBlock(a));
2427 SetInt(a, methraw->numargs);
2428 return errNone;
2431 int prFunDef_NumVars(struct VMGlobals *g, int numArgsPushed);
2432 int prFunDef_NumVars(struct VMGlobals *g, int numArgsPushed)
2434 PyrSlot *a;
2435 PyrMethodRaw *methraw;
2437 a = g->sp;
2438 methraw = METHRAW(slotRawBlock(a));
2439 SetInt(a, methraw->numvars);
2440 return errNone;
2443 int prFunDef_VarArgs(struct VMGlobals *g, int numArgsPushed);
2444 int prFunDef_VarArgs(struct VMGlobals *g, int numArgsPushed)
2446 PyrSlot *a;
2447 PyrMethodRaw *methraw;
2449 a = g->sp;
2450 methraw = METHRAW(slotRawBlock(a));
2451 if (methraw->varargs) { SetTrue(a); } else { SetFalse(a); }
2452 return errNone;
2456 int undefinedPrimitive(struct VMGlobals *g, int numArgsPushed)
2458 error("A primitive was not bound. %d %d\n", g->primitiveIndex, gPrimitiveTable.size);
2459 dumpObject((PyrObject*)g->primitiveMethod);
2460 return errFailed;
2463 void dumpByteCodes(PyrBlock *theBlock);
2465 int prDumpByteCodes(struct VMGlobals *g, int numArgsPushed)
2467 PyrSlot *a;
2469 a = g->sp;
2470 dumpByteCodes(slotRawBlock(a));
2471 return errNone;
2474 int prObjectPointsTo(struct VMGlobals *g, int numArgsPushed)
2476 PyrSlot *a, *b, temp;
2477 PyrObject *obj;
2478 int i;
2480 a = g->sp - 1;
2481 b = g->sp;
2483 if (NotObj(a)) slotCopy(a,&o_false);
2484 else {
2485 obj = slotRawObject(a);
2486 for (i=0; i<obj->size; ++i) {
2487 getIndexedSlot(obj, &temp, i);
2488 if (SlotEq(&temp, b)) {
2489 slotCopy(a,&o_true);
2490 return errNone;
2493 slotCopy(a,&o_false);
2495 return errNone;
2499 int prObjectRespondsTo(struct VMGlobals *g, int numArgsPushed)
2501 PyrSlot *a, *b;
2502 PyrClass *classobj;
2503 PyrMethod *meth;
2504 PyrSymbol *selector;
2505 int index;
2507 a = g->sp - 1;
2508 b = g->sp;
2510 classobj = classOfSlot(a);
2512 if (IsSym(b)) {
2514 selector = slotRawSymbol(b);
2515 index = slotRawInt(&classobj->classIndex) + selector->u.index;
2516 meth = gRowTable[index];
2517 if (slotRawSymbol(&meth->name) != selector) {
2518 slotCopy(a,&o_false);
2519 } else {
2520 slotCopy(a,&o_true);
2522 } else if (isKindOfSlot(b, class_array)) {
2523 int size = slotRawObject(b)->size;
2524 PyrSlot *slot = slotRawObject(b)->slots;
2525 for (int i=0; i<size; ++i, ++slot) {
2527 if (NotSym(slot)) return errWrongType;
2529 selector = slotRawSymbol(slot);
2530 index = slotRawInt(&classobj->classIndex) + selector->u.index;
2531 meth = gRowTable[index];
2532 if (slotRawSymbol(&meth->name) != selector) {
2533 slotCopy(a,&o_false);
2534 return errNone;
2537 slotCopy(a,&o_true);
2538 } else return errWrongType;
2539 return errNone;
2542 PyrMethod* GetFunctionCompileContext(VMGlobals* g);
2543 PyrMethod* GetFunctionCompileContext(VMGlobals* g)
2545 PyrClass *classobj;
2546 PyrSymbol *classsym, *contextsym;
2547 PyrMethod *meth;
2548 // lookup interpreter class
2549 classsym = getsym("Interpreter");
2550 classobj = classsym->u.classobj;
2551 if (!classobj) {
2552 error("There is no Interpreter class.\n");
2553 return 0;
2555 // lookup functionCompileContext method
2556 contextsym = getsym("functionCompileContext");
2557 int index = slotRawInt(&classobj->classIndex) + contextsym->u.index;
2558 meth = gRowTable[index];
2559 if (!meth || slotRawSymbol(&meth->name) != contextsym) {
2560 error("compile context method 'functionCompileContext' not found.\n");
2561 return 0;
2563 gCompilingClass = classobj;
2564 gCompilingMethod = meth;
2565 gCompilingBlock = (PyrBlock*)meth;
2566 return meth;
2569 #if !SCPLAYER
2570 int prCompileString(struct VMGlobals *g, int numArgsPushed)
2572 PyrSlot *a, *b;
2573 PyrString *string;
2574 PyrMethod *meth;
2576 a = g->sp - 1;
2577 b = g->sp;
2579 // check b is a string
2580 if (NotObj(b)) return errWrongType;
2581 if (!isKindOf(slotRawObject(b), class_string)) return errWrongType;
2582 string = slotRawString(b);
2584 gRootParseNode = NULL;
2585 initParserPool();
2586 //assert(g->gc->SanityCheck());
2587 startLexerCmdLine(string->s, string->size);
2588 compileErrors = 0;
2589 compilingCmdLine = true;
2590 gCompilingVMGlobals = g;
2591 compilingCmdLineErrorWindow = false;
2592 //assert(g->gc->SanityCheck());
2593 parseFailed = yyparse();
2594 //assert(g->gc->SanityCheck());
2595 if (!parseFailed && gRootParseNode) {
2596 PyrSlot slotResult;
2598 meth = GetFunctionCompileContext(g);
2599 if (!meth) return errFailed;
2601 ((PyrBlockNode*)gRootParseNode)->mIsTopLevel = true;
2603 SetNil(&slotResult);
2604 COMPILENODE(gRootParseNode, &slotResult, true);
2606 if (NotObj(&slotResult)
2607 || slotRawObject(&slotResult)->classptr != class_fundef) {
2608 compileErrors++;
2609 error("Compile did not return a FunctionDef..\n");
2611 if (compileErrors) {
2612 SetNil(a);
2613 } else {
2614 PyrBlock *block;
2615 PyrClosure *closure;
2617 block = slotRawBlock(&slotResult);
2618 // create a closure
2619 closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, false);
2620 closure->classptr = class_func;
2621 closure->size = 2;
2622 SetObject(&closure->block, block);
2623 slotCopy(&closure->context,&slotRawInterpreter(&g->process->interpreter)->context);
2624 SetObject(a, closure);
2626 } else {
2627 if (parseFailed) {
2628 compileErrors++;
2629 error("Command line parse failed\n");
2630 } else {
2631 postfl("<nothing to do>\n");
2633 SetNil(a);
2635 finiLexer();
2636 freeParserPool();
2638 pyr_pool_compile->FreeAll();
2639 //flushErrors();
2640 compilingCmdLine = false;
2642 return !(parseFailed || compileErrors) ? errNone : errFailed;
2644 #endif
2646 char sCodeStringIn[8192];
2647 char sCodeStringOut[8192];
2649 int prUGenCodeString(struct VMGlobals *g, int numArgsPushed);
2650 int prUGenCodeString(struct VMGlobals *g, int numArgsPushed)
2652 PyrSlot *aa, *bb, *cc, *dd, *ee;
2653 char *out = sCodeStringOut;
2654 char ugenPrefix[16];
2655 int err;
2657 aa = g->sp - 4; // code string
2658 bb = g->sp - 3; // ugen prefix
2659 ee = g->sp - 2; // isDecl
2660 cc = g->sp - 1; // input names
2661 dd = g->sp; // input value strings
2663 int ugenIndex;
2664 err = slotIntVal(bb, &ugenIndex);
2665 if (err) return err;
2666 if (!isKindOfSlot(cc, class_array) && !isKindOfSlot(cc, class_symbolarray)) return errWrongType;
2667 if (!isKindOfSlot(dd, class_array)) return errWrongType;
2668 bool isDecl = IsTrue(ee);
2670 PyrObject *inputNamesObj = slotRawObject(cc);
2671 PyrObject *inputStringsObj = slotRawObject(dd);
2673 sprintf(ugenPrefix, "u%d", ugenIndex);
2674 int ugenPrefixSize = strlen(ugenPrefix);
2675 PyrString* codeStringObj = slotRawString(aa);
2676 int codeStringSize = codeStringObj->size;
2677 if (codeStringSize > 8000) {
2678 error("input string too int.\n");
2679 return errFailed;
2681 memcpy(sCodeStringIn, codeStringObj->s, codeStringSize);
2682 sCodeStringIn[codeStringSize] = 0;
2684 char* in = sCodeStringIn;
2685 int c;
2686 while ((c = *in++) != 0) {
2687 if (c == '@') {
2688 if (!isDecl) {
2689 if (*in != '@') {
2690 *out++ = 's';
2691 *out++ = '-';
2692 *out++ = '>';
2693 } else in++;
2695 for (int j=0; j<ugenPrefixSize; ++j) {
2696 *out++ = ugenPrefix[j];
2698 } else if (c == '$') {
2699 char name[64];
2700 int j=0;
2701 do {
2702 c = *in++;
2703 if (c == 0) break;
2704 if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))) {
2705 --in;
2706 break;
2708 name[j++] = c;
2709 } while (c);
2711 bool found = false;
2712 int nameSize = j;
2713 int slotIndex = -1;
2714 for (int j=0; j<inputNamesObj->size; ++j) {
2715 PyrSlot inputNameSlot;
2716 getIndexedSlot(inputNamesObj, &inputNameSlot, j);
2717 if (!IsSym(&inputNameSlot)) return errWrongType;
2718 PyrSymbol* inputSym = slotRawSymbol(&inputNameSlot);
2719 char *inputName = inputSym->name;
2720 int inputNameSize = inputSym->length;
2721 if (inputNameSize == nameSize && strncmp(inputName, name, nameSize)==0) {
2722 found = true;
2723 slotIndex = j;
2724 break;
2727 if (slotIndex >= 0) {
2728 PyrSlot *inputStringSlot = inputStringsObj->slots + slotIndex;
2729 if (!isKindOfSlot(inputStringSlot, class_string)) return errWrongType;
2730 PyrString *inputStringObj = slotRawString(inputStringSlot);
2731 char *input = inputStringObj->s;
2732 int inputStringSize = inputStringObj->size;
2733 for (int j=0; j<inputStringSize; ++j) {
2734 *out++ = input[j];
2736 } else {
2737 *out++ = '?'; *out++ = '?';
2738 for (int j=0; j<nameSize; ++j) {
2739 *out++ = name[j];
2741 *out++ = '?'; *out++ = '?';
2743 } else {
2744 *out++ = c;
2746 if (out - sCodeStringOut > 8000) {
2747 *out++ = '\n';
2748 *out++ = '.';
2749 *out++ = '.';
2750 *out++ = '.';
2751 *out++ = '\n';
2752 break;
2755 *out++ = 0;
2756 PyrString* outString = newPyrString(g->gc, sCodeStringOut, 0, true);
2757 SetObject(aa, outString);
2759 return errNone;
2764 /*void threadSanity(VMGlobals *g, PyrThread *thread);
2765 void threadSanity(VMGlobals *g, PyrThread *thread)
2767 int state;
2768 g->gc->numToScan = 1000000;
2769 doGC(g, 0);
2770 assert(g->gc->SanityCheck());
2772 state = slotRawInt(&thread->state);
2773 if (state == tYield) {
2774 if (!IsObj(&thread->method)) { error("thread method not an Object\n"); }
2775 else if (!isKindOf(slotRawObject(&thread->method), class_method)) { error("thread method not a Method\n"); }
2776 else if (slotRawObject(&thread->method)->gc_color == gcColor.gcFree) { error("thread method is FREE\n"); }
2778 if (!IsObj(&thread->block)) { error("thread block not an Object\n"); }
2779 else if (!isKindOf(slotRawObject(&thread->block), class_func)) { error("thread block not a Function\n"); }
2780 else if (slotRawObject(&thread->block)->gc_color == gcColor.gcFree) { error("thread block is FREE\n"); }
2782 if (IsObj(&thread->receiver) &slotRawObject(&& thread->receiver)->gc_color == gcColor.gcFree)
2783 { error("thread receiver is FREE\n"); }
2785 FrameSanity(thread->frame.uof);
2787 oldthread->method.uom = g->method;
2788 oldthread->block.uoblk = g->block;
2789 SetObject(&oldthread->frame, g->frame);
2790 slotRawInt(&oldthread->ip) = (int)g->ip;
2791 slotRawInt(&oldthread->sp) = (int)g->sp;
2794 } else if (state == tInit) {
2795 } else {
2796 postfl("bad state\n");
2801 PyrSymbol *s_prready;
2802 PyrSymbol *s_prrunnextthread;
2804 void switchToThread(VMGlobals *g, PyrThread *newthread, int oldstate, int *numArgsPushed);
2805 void switchToThread(VMGlobals *g, PyrThread *newthread, int oldstate, int *numArgsPushed)
2807 PyrThread *oldthread;
2808 PyrGC *gc;
2809 PyrFrame *frame;
2811 #if TAILCALLOPTIMIZE
2812 g->tailCall = 0; // ?? prevent a crash. is there a way to allow a TCO ?
2813 #endif
2815 oldthread = g->thread;
2816 if (newthread == oldthread) return;
2817 //postfl("->switchToThread %d %p -> %p\n", oldstate, oldthread, newthread);
2818 //post("->switchToThread from %s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name);
2819 //post("->stack %p g->sp %p [%d] g->top %p [%d]\n",
2820 // g->gc->Stack()->slots, g->sp, g->sp - g->gc->Stack()->slots, g->top, g->top - g->gc->Stack()->slots);
2821 //assert(g->gc->SanityCheck());
2822 //CallStackSanity(g, "switchToThreadA");
2823 //gcDumpInfo(g->gc);
2824 gc = g->gc;
2826 // save environment in oldthread
2827 PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1];
2828 slotCopy(&oldthread->environment,currentEnvironmentSlot);
2829 gc->GCWrite(oldthread, currentEnvironmentSlot);
2831 SetRaw(&oldthread->state, oldstate);
2833 if (oldstate == tDone) {
2834 SetObject(&oldthread->stack, gc->Stack());
2835 gc->ToWhite(gc->Stack());
2836 gc->Stack()->size = 0;
2837 gc->GCWrite(oldthread, gc->Stack());
2838 SetNil(&oldthread->method);
2839 SetNil(&oldthread->block);
2840 SetNil(&oldthread->receiver);
2841 SetNil(&oldthread->frame);
2842 SetRaw(&oldthread->ip, (void*)0);
2843 SetRaw(&oldthread->sp, (void*)0);
2844 SetRaw(&oldthread->numArgsPushed, 0);
2845 SetRaw(&oldthread->numpop, 0);
2846 SetNil(&oldthread->parent);
2847 } else if (oldstate == tInit) {
2848 SetObject(&oldthread->stack, gc->Stack());
2849 gc->ToWhite(gc->Stack());
2850 gc->Stack()->size = 0;
2851 gc->GCWrite(oldthread, gc->Stack());
2852 SetNil(&oldthread->method);
2853 SetNil(&oldthread->block);
2854 SetNil(&oldthread->receiver);
2855 SetNil(&oldthread->frame);
2856 SetRaw(&oldthread->ip, (void*)0);
2857 SetRaw(&oldthread->sp, (void*)0);
2858 SetRaw(&oldthread->numArgsPushed, 0);
2859 SetRaw(&oldthread->numpop, 0);
2860 SetNil(&oldthread->parent);
2861 } else {
2862 // save old thread's state
2863 SetObject(&oldthread->stack, gc->Stack());
2864 gc->ToWhite(gc->Stack());
2865 gc->Stack()->size = g->sp - gc->Stack()->slots + 1;
2866 //post("else %p %p\n", slotRawObject(&oldthread->stack), gc->Stack());
2868 SetObject(&oldthread->method, g->method);
2869 SetObject(&oldthread->block, g->block);
2870 SetObject(&oldthread->frame, g->frame);
2871 SetPtr(&oldthread->ip, g->ip);
2872 SetPtr(&oldthread->sp, g->sp);
2873 slotCopy(&oldthread->receiver,&g->receiver);
2874 SetRaw(&oldthread->numArgsPushed, *numArgsPushed);
2875 SetRaw(&oldthread->numpop, g->numpop);
2877 //gc->ToGrey(oldthread);
2878 if (gc->ObjIsBlack(oldthread)) {
2879 gc->GCWriteBlack(gc->Stack());
2880 gc->GCWriteBlack(g->method);
2881 gc->GCWriteBlack(g->block);
2883 frame = slotRawFrame(&oldthread->frame);
2884 gc->GCWriteBlack(frame);
2886 gc->GCWriteBlack(&g->receiver);
2890 // restore new thread's state
2891 g->thread = newthread;
2892 SetObject(&g->process->curThread, newthread);
2893 gc->GCWrite(g->process, newthread);
2895 gc->SetStack(slotRawObject(&newthread->stack));
2896 gc->ToBlack(gc->Stack());
2897 SetNil(&newthread->stack);
2899 g->method = slotRawMethod(&newthread->method);
2900 g->block = slotRawBlock(&newthread->block);
2901 g->frame = slotRawFrame(&newthread->frame);
2902 g->ip = (unsigned char *)slotRawPtr(&newthread->ip);
2903 g->sp = (PyrSlot*)slotRawPtr(&newthread->sp);
2904 slotCopy(&g->receiver,&newthread->receiver);
2906 g->rgen = (RGen*)(slotRawObject(&newthread->randData)->slots);
2908 *numArgsPushed = slotRawInt(&newthread->numArgsPushed);
2910 // these are perhaps unecessary because a thread may not
2911 // legally block within a C primitive
2912 g->numpop = slotRawInt(&newthread->numpop);
2914 g->execMethod = 99;
2916 //post("switchToThread ip %p\n", g->ip);
2917 //post(slotRawInt(&"switchToThread newthread->ip) %d\n", slotRawInt(&newthread->ip));
2918 //post(slotRawInt(&"switchToThread oldthread->ip) %d\n", slotRawInt(&oldthread->ip));
2920 // wipe out values which will become stale as new thread executes:
2921 SetNil(&newthread->method);
2922 SetNil(&newthread->block);
2923 SetNil(&newthread->frame);
2924 SetRaw(&newthread->ip, (void*)0);
2925 SetRaw(&newthread->sp, (void*)0);
2926 SetNil(&newthread->receiver);
2928 SetRaw(&newthread->state, tRunning);
2931 // set new environment
2932 slotCopy(currentEnvironmentSlot,&g->thread->environment);
2933 g->gc->GCWrite(g->classvars, currentEnvironmentSlot);
2935 //post("old thread %p stack %p\n", oldthread, slotRawObject(&oldthread->stack));
2936 //post("new thread %p stack %p\n", g->thread, slotRawObject(&g->thread->stack));
2937 //post("main thread %p stack %p\n", slotRawThread(&g->process->mainThread), slotRawObject(&slotRawThread(&g->process->mainThread)->stack));
2939 //postfl("<-switchToThread\n");
2940 //post("<-stack %p g->sp %p [%d] g->top %p [%d]\n",
2941 // g->gc->Stack()->slots, g->sp, g->sp - g->gc->Stack()->slots, g->top, g->top - g->gc->Stack()->slots);
2942 //assert(g->gc->SanityCheck());
2943 //CallStackSanity(g, "switchToThreadB");
2944 //post("switchToThread ip2 %p\n", g->ip);
2947 void initPyrThread(VMGlobals *g, PyrThread *thread, PyrSlot *func, int stacksize, PyrInt32Array* rgenArray,
2948 double beats, double seconds, PyrSlot* clock, bool collect);
2949 void initPyrThread(VMGlobals *g, PyrThread *thread, PyrSlot *func, int stacksize, PyrInt32Array* rgenArray,
2950 double beats, double seconds, PyrSlot* clock, bool collect)
2952 PyrObject *array;
2953 PyrGC* gc = g->gc;
2955 slotCopy(&thread->func, func);
2956 gc->GCWrite(thread, func);
2958 array = newPyrArray(gc, stacksize, 0, collect);
2959 SetObject(&thread->stack, array);
2960 gc->GCWrite(thread, array);
2962 SetInt(&thread->state, tInit);
2964 SetPtr(&thread->ip, 0);
2965 SetPtr(&thread->sp, 0);
2967 SetObject(&thread->randData, rgenArray);
2968 gc->GCWrite(thread, rgenArray);
2970 SetFloat(&thread->beats, beats);
2971 SetFloat(&thread->seconds, seconds);
2972 SetInt(&thread->numArgsPushed, 0);
2973 SetInt(&thread->numpop, 0);
2975 if (IsNil(clock)) {
2976 SetObject(&thread->clock, s_systemclock->u.classobj);
2977 } else {
2978 slotCopy(&thread->clock,clock);
2979 gc->GCWrite(thread, clock);
2982 PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1];
2983 slotCopy(&thread->environment,currentEnvironmentSlot);
2984 gc->GCWrite(thread, currentEnvironmentSlot);
2986 if(g->process) { // check we're not just starting up
2987 PyrSlot* executingPath = &g->process->nowExecutingPath;
2988 slotCopy(&thread->executingPath,&g->process->nowExecutingPath);
2989 gc->GCWrite(thread, &g->process->nowExecutingPath);
2992 SetInt(&thread->stackSize, stacksize);
2995 extern PyrSymbol *s_prstart;
2997 int prThreadInit(struct VMGlobals *g, int numArgsPushed);
2998 int prThreadInit(struct VMGlobals *g, int numArgsPushed)
3000 PyrSlot *a, *b, *c, *d;
3001 int stacksize, err;
3002 PyrThread *thread;
3004 //postfl("->prThreadInit\n");
3005 //assert(g->gc->SanityCheck());
3006 //CallStackSanity(g, "prThreadInit");
3007 a = g->sp - 2; // thread
3008 b = g->sp - 1; // function
3009 c = g->sp; // stacksize
3011 thread = slotRawThread(a);
3013 if (NotObj(b) || !isKindOf(slotRawObject(b), class_func)) {
3014 error("Thread function arg not a Function.\n");
3015 return errWrongType;
3018 err = slotIntVal(c, &stacksize);
3019 if (err) return err;
3021 stacksize = std::max(stacksize, EVALSTACKDEPTH);
3023 initPyrThread(g, thread, b, stacksize, (PyrInt32Array*)(slotRawObject(&g->thread->randData)),
3024 slotRawFloat(&g->thread->beats), slotRawFloat(&g->thread->seconds), &g->thread->clock, true);
3026 //postfl("<-prThreadInit\n");
3027 //assert(g->gc->SanityCheck());
3028 //CallStackSanity(g, "<prThreadInit");
3029 return errNone;
3032 int prThreadRandSeed(struct VMGlobals *g, int numArgsPushed);
3033 int prThreadRandSeed(struct VMGlobals *g, int numArgsPushed)
3035 PyrSlot *a = g->sp - 1; // thread
3036 PyrSlot *b = g->sp; // rand seed
3038 PyrThread *thread = slotRawThread(a);
3040 int32 seed;
3041 int err = slotIntVal(b, &seed);
3042 if (err) return err;
3044 PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, true);
3045 rgenArray->size = 4;
3046 ((RGen*)(rgenArray->i))->init(seed);
3048 if (thread == g->thread) {
3049 g->rgen = (RGen*)(rgenArray->i);
3051 SetObject(&thread->randData, rgenArray);
3052 g->gc->GCWrite(thread, rgenArray);
3054 return errNone;
3057 int prThreadGetRandData(struct VMGlobals *g, int numArgsPushed);
3058 int prThreadGetRandData(struct VMGlobals *g, int numArgsPushed)
3060 PyrSlot *a = g->sp; // thread
3062 PyrThread *thread = slotRawThread(a);
3064 RGen* rgen = (RGen*)slotRawObject(&thread->randData)->slots;
3066 PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, false);
3067 rgenArray->size = 3;
3069 rgenArray->i[0] = rgen->s1;
3070 rgenArray->i[1] = rgen->s2;
3071 rgenArray->i[2] = rgen->s3;
3073 SetObject(a, rgenArray);
3074 return errNone;
3077 int prThreadSetRandData(struct VMGlobals *g, int numArgsPushed);
3078 int prThreadSetRandData(struct VMGlobals *g, int numArgsPushed)
3080 PyrSlot *a = g->sp - 1; // thread
3081 PyrSlot *b = g->sp; // rand data array
3083 if (!isKindOfSlot(b, class_int32array)) return errWrongType;
3084 if (slotRawObject(b)->size < 3) return errWrongType;
3086 PyrThread *thread = slotRawThread(a);
3088 RGen* rgen = (RGen*)slotRawObject(&thread->randData)->slots;
3090 PyrInt32Array *rgenArray = (PyrInt32Array*)slotRawObject(b);
3092 rgen->s1 = rgenArray->i[0];
3093 rgen->s2 = rgenArray->i[1];
3094 rgen->s3 = rgenArray->i[2];
3096 return errNone;
3099 #if 0
3100 int32 timeseed();
3102 int transformMainThreadToRoutine(VMGlobals *g)
3104 PyrProcess* process = g->process;
3105 if (g->thread != process->mainThread.uot) return errFailed;
3106 //if (g->thread != process->curThread.uot) return errFailed;
3108 PyrThread* curthread = (PyrThread*)slotRawObject(&process->mainThread);
3110 // create a new main thread
3111 PyrThread* newthread = (PyrThread*)instantiateObject(g->gc, class_thread, 0, true, false);
3113 PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, false);
3114 rgenArray->size = 4;
3115 ((RGen*)(rgenArray->i))->init(timeseed());
3117 PyrSlot clockSlot;
3118 SetObject(&clockSlot, s_systemclock->u.classobj);
3119 initPyrThread(g, newthread, &o_nil, EVALSTACKDEPTH, rgenArray, 0., 0., &clockSlot, false);
3120 slotRawInt(&newthread->sp) = (int)slotRawObject(&newthread->stack)->slots - 1;
3121 SetObject(&process->mainThread, newthread);
3122 g->gc->GCWrite(process, newthread);
3124 curthread->classptr = class_routine;
3125 PyrSlot *cmdFunc = &process->interpreter.uoi->cmdFunc;
3126 slotCopy(&curthread->func,cmdFunc);
3127 g->gc->GCWrite(curthread, cmdFunc);
3129 return errNone;
3132 void schedAdd(VMGlobals *g, PyrObject* inQueue, double inSeconds, PyrSlot* inTask);
3133 #endif
3136 int prRoutineYield(struct VMGlobals *g, int numArgsPushed);
3137 int prRoutineYield(struct VMGlobals *g, int numArgsPushed)
3139 PyrSlot value;
3141 //postfl("->prRoutineYield %p\n", g->thread);
3142 //assert(g->gc->SanityCheck());
3143 //CallStackSanity(g, "prRoutineYield");
3144 //postfl("->numArgsPushed %d\n", numArgsPushed);
3146 slotCopy(&value,g->sp);
3148 if (!isKindOf((PyrObject*)g->thread, class_routine)) {
3149 error ("yield was called outside of a Routine.\n");
3150 return errFailed;
3153 PyrThread *parent = slotRawThread(&g->thread->parent);
3154 SetNil(&g->thread->parent);
3155 slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath);
3156 //debugf("yield from thread %p to parent %p\n", g->thread, slotRawThread(&g->thread->parent));
3157 switchToThread(g, parent, tSuspended, &numArgsPushed);
3159 // on the other side of the looking glass, put the yielded value on the stack as the result..
3160 slotCopy((g->sp - numArgsPushed + 1),&value);
3162 //postfl("<-numArgsPushed %d\n", numArgsPushed);
3163 //postfl("<-prRoutineYield\n");
3164 //assert(g->gc->SanityCheck());
3165 //CallStackSanity(g, "<prRoutineYield");
3166 return errNone;
3169 int prRoutineAlwaysYield(struct VMGlobals *g, int numArgsPushed);
3170 int prRoutineAlwaysYield(struct VMGlobals *g, int numArgsPushed)
3172 PyrSlot value;
3174 //postfl("->prRoutineAlwaysYield ip %p\n", g->ip);
3175 //assert(g->gc->SanityCheck());
3176 //CallStackSanity(g, "prRoutineAlwaysYield");
3177 if (!isKindOf((PyrObject*)g->thread, class_routine)) {
3178 error ("alwaysYield was called outside of a Routine.\n");
3179 return errFailed;
3182 slotCopy(&value,g->sp);
3183 slotCopy(&g->thread->terminalValue,&value);
3184 g->gc->GCWrite(g->thread, g->sp);
3186 PyrThread *parent = slotRawThread(&g->thread->parent);
3187 SetNil(&g->thread->parent);
3188 slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath);
3189 //post("alwaysYield from thread %p to parent %p\n", g->thread, parent);
3190 switchToThread(g, parent, tDone, &numArgsPushed);
3192 // on the other side of the looking glass, put the yielded value on the stack as the result..
3193 slotCopy((g->sp - numArgsPushed + 1),&value);
3195 //postfl("<-prRoutineAlwaysYield ip %p\n", g->ip);
3196 //assert(g->gc->SanityCheck());
3197 //CallStackSanity(g, "<prRoutineAlwaysYield");
3198 return errNone;
3201 int prRoutineResume(struct VMGlobals *g, int numArgsPushed);
3202 int prRoutineResume(struct VMGlobals *g, int numArgsPushed)
3204 PyrSlot *a, *b, threadSlot, value;
3205 PyrThread *thread;
3206 int state;
3208 //assert(g->gc->SanityCheck());
3209 //CallStackSanity(g, "prRoutineResume");
3210 a = g->sp - 1;
3211 b = g->sp;
3213 thread = slotRawThread(a);
3214 state = slotRawInt(&thread->state);
3215 //postfl("->prRoutineResume %d\n", state);
3217 slotCopy(&thread->oldExecutingPath,&g->process->nowExecutingPath);
3218 slotCopy(&g->process->nowExecutingPath, &thread->executingPath);
3219 if (state == tInit) {
3220 slotCopy(&threadSlot,a);
3221 slotCopy(&value,b);
3223 //post("g->thread %p\n", g->thread);
3224 //post("thread %p\n", thread);
3225 SetObject(&thread->parent, g->thread);
3226 g->gc->GCWrite(thread, g->thread);
3228 SetRaw(&thread->beats, slotRawFloat(&g->thread->beats));
3229 SetRaw(&thread->seconds, slotRawFloat(&g->thread->seconds));
3230 slotCopy(&thread->clock, &g->thread->clock);
3231 g->gc->GCWrite(thread, &g->thread->clock);
3233 //postfl("start into thread %p from parent %p\n", thread, g->thread);
3234 switchToThread(g, thread, tSuspended, &numArgsPushed);
3236 // set stack
3237 //post("set stack %p %p\n", g->sp, g->gc->Stack()->slots - 1);
3238 g->sp = g->gc->Stack()->slots - 1;
3239 slotCopy((++g->sp), &threadSlot);
3240 slotCopy(&g->receiver, &threadSlot);
3241 slotCopy((++g->sp),&value);
3243 sendMessage(g, s_prstart, 2);
3244 } else if (state == tSuspended) {
3246 if (IsNil(&thread->parent)) {
3247 SetObject(&thread->parent, g->thread);
3249 g->gc->GCWrite(thread, g->thread);
3251 SetRaw(&thread->beats, slotRawFloat(&g->thread->beats));
3252 SetRaw(&thread->seconds, slotRawFloat(&g->thread->seconds));
3253 slotCopy(&thread->clock,&g->thread->clock);
3254 g->gc->GCWrite(thread, &g->thread->clock);
3256 slotCopy(&value,b);
3257 //debugf("resume into thread %p from parent %p\n", thread, g->thread);
3258 switchToThread(g, thread, tSuspended, &numArgsPushed);
3259 // on the other side of the looking glass, put the yielded value on the stack as the result..
3260 slotCopy((g->sp - numArgsPushed + 1),&value);
3261 } else if (state == tDone) {
3262 slotCopy(a,&thread->terminalValue);
3263 } else if (state == tRunning) {
3264 error("Tried to resume the running thread.\n");
3265 return errFailed;
3266 } else {
3267 error("Thread in strange state: %d\n", state);
3268 return errFailed;
3270 //postfl("<-prRoutineResume\n");
3271 //CallStackSanity(g);
3272 return errNone;
3275 int prRoutineReset(struct VMGlobals *g, int numArgsPushed);
3276 int prRoutineReset(struct VMGlobals *g, int numArgsPushed)
3278 PyrThread *thread;
3279 int state;
3281 //assert(g->gc->SanityCheck());
3282 //CallStackSanity(g, "prRoutineReset");
3283 thread = slotRawThread(g->sp);
3284 state = slotRawInt(&thread->state);
3285 //post("->prRoutineReset %d\n", state);
3286 if (state == tSuspended) {
3287 SetRaw(&thread->state, tInit);
3288 slotRawObject(&thread->stack)->size = 0;
3289 SetNil(&thread->method);
3290 SetNil(&thread->block);
3291 SetNil(&thread->receiver);
3292 SetNil(&thread->frame);
3293 SetRaw(&thread->ip, (void*)0);
3294 SetRaw(&thread->sp, (void*)0);
3295 SetRaw(&thread->numArgsPushed, 0);
3296 SetRaw(&thread->numpop, 0);
3297 SetNil(&thread->parent);
3298 } else if (state == tDone) {
3299 SetRaw(&thread->state, tInit);
3300 slotRawObject(&thread->stack)->size = 0;
3301 SetNil(&thread->method);
3302 SetNil(&thread->block);
3303 SetNil(&thread->receiver);
3304 SetNil(&thread->frame);
3305 SetRaw(&thread->ip, (void*)0);
3306 SetRaw(&thread->sp, (void*)0);
3307 SetRaw(&thread->numArgsPushed, 0);
3308 SetRaw(&thread->numpop, 0);
3309 SetNil(&thread->parent);
3310 } else if (state == tInit) {
3311 // do nothing
3312 } else if (state == tRunning) {
3313 error("A Routine cannot reset itself except by yieldAndReset.\n");
3314 return errFailed;
3315 } else {
3316 error("Routine in unknown state. %d\n", state);
3317 return errFailed;
3319 //assert(g->gc->SanityCheck());
3320 //CallStackSanity(g, "<prRoutineReset");
3321 return errNone;
3324 int prRoutineStop(struct VMGlobals *g, int numArgsPushed);
3325 int prRoutineStop(struct VMGlobals *g, int numArgsPushed)
3327 PyrThread *thread;
3328 int state;
3329 //post("->prRoutineStop\n");
3330 //assert(g->gc->SanityCheck());
3331 //CallStackSanity(g, "prRoutineStop");
3333 thread = slotRawThread(g->sp);
3334 state = slotRawInt(&thread->state);
3337 if (state == tSuspended || state == tInit) {
3338 slotCopy(&g->process->nowExecutingPath, &thread->oldExecutingPath);
3339 SetNil(&g->thread->terminalValue);
3340 SetRaw(&thread->state, tDone);
3341 slotRawObject(&thread->stack)->size = 0;
3342 } else if (state == tDone) {
3343 // do nothing
3344 } else if (state == tRunning) {
3345 error("Do not call .stop from within the Routine.\n");
3346 post("A Routine should stop itself using nil.alwaysYield.\n");
3347 return errFailed;
3348 } else {
3349 error("Routine in unknown state. %d\n", state);
3350 return errFailed;
3352 //assert(g->gc->SanityCheck());
3353 //CallStackSanity(g, "<prRoutineStop");
3354 return errNone;
3358 int prRoutineYieldAndReset(struct VMGlobals *g, int numArgsPushed);
3359 int prRoutineYieldAndReset(struct VMGlobals *g, int numArgsPushed)
3361 PyrSlot *a, *b, value;
3362 int state;
3364 //post("->prRoutineYieldAndReset\n");
3365 //assert(g->gc->SanityCheck());
3366 //CallStackSanity(g, "prRoutineYieldAndReset");
3367 a = g->sp - 1;
3368 b = g->sp;
3370 if (!isKindOf((PyrObject*)g->thread, class_routine)) {
3371 error ("yieldAndReset was called outside of a Routine.\n");
3372 return errFailed;
3374 /*if (!slotRawThread(&g->thread->parent)) {
3375 error ("yieldAndReset was called from a thread with no parent.\n");
3376 return errFailed;
3378 slotCopy(&value,a);
3380 if (IsFalse(b)) state = tSuspended;
3381 else state = tInit;
3383 PyrThread *parent = slotRawThread(&g->thread->parent);
3384 SetNil(&g->thread->parent);
3385 switchToThread(g, parent, state, &numArgsPushed);
3386 // on the other side of the looking glass, put the yielded value on the stack as the result..
3387 slotCopy((g->sp - numArgsPushed + 1),&value);
3389 //slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath);
3391 //post("<-prRoutineYieldAndReset\n");
3392 //assert(g->gc->SanityCheck());
3393 //CallStackSanity(g, "prRoutineYieldAndReset");
3394 return errNone;
3398 bool gBlork = false;
3400 int prBlork(struct VMGlobals *g, int numArgsPushed);
3401 int prBlork(struct VMGlobals *g, int numArgsPushed)
3403 PyrSlot *a;
3405 a = g->sp;
3406 if (IsTrue(a)) gBlork = true;
3407 else gBlork = false;
3409 return errNone;
3412 int prOverwriteMsg(struct VMGlobals *g, int numArgsPushed);
3413 int prOverwriteMsg(struct VMGlobals *g, int numArgsPushed)
3415 PyrSlot *a = g->sp;
3416 PyrString* string = newPyrString(g->gc, overwriteMsg.c_str(), 0, false);
3417 SetObject(a, string);
3418 return errNone;
3421 int prAppClockSchedNotify(struct VMGlobals *g, int numArgsPushed)
3423 //NOTE: the _AppClock_SchedNotify primitive shall be redefined by language clients
3424 // if they wish to respond to AppClock scheduling notifications
3425 return errNone;
3428 enum {includePaths, excludePaths};
3430 static int prLanguageConfig_getLibraryPaths(struct VMGlobals * g, int numArgsPushed, int pathType)
3432 PyrSlot *result = g->sp;
3434 typedef SC_LanguageConfig::DirVector DirVector;
3436 DirVector const & dirVector = (pathType == includePaths) ? gLibraryConfig->includedDirectories()
3437 : gLibraryConfig->excludedDirectories();
3439 size_t numberOfPaths = dirVector.size();
3440 PyrObject * resultArray = newPyrArray(g->gc, numberOfPaths, 0, true);
3441 SetObject(result, resultArray);
3442 resultArray->size = numberOfPaths;
3444 for (size_t i = 0; i != numberOfPaths; ++i)
3445 SetObject(resultArray->slots + i, newPyrString(g->gc, dirVector[i].c_str(), 0, true));
3446 return errNone;
3449 static int prLanguageConfig_getIncludePaths(struct VMGlobals * g, int numArgsPushed)
3451 return prLanguageConfig_getLibraryPaths(g, numArgsPushed, includePaths);
3454 static int prLanguageConfig_getExcludePaths(struct VMGlobals * g, int numArgsPushed)
3456 return prLanguageConfig_getLibraryPaths(g, numArgsPushed, excludePaths);
3459 static int prLanguageConfig_addLibraryPath(struct VMGlobals * g, int numArgsPushed, int pathType)
3461 PyrSlot *result = g->sp - 1;
3462 PyrSlot *removeString = g->sp;
3464 char path[MAXPATHLEN];
3465 bool error = slotStrVal(removeString, path, MAXPATHLEN);
3466 if (error)
3467 return errWrongType;
3469 if (pathType == includePaths)
3470 gLibraryConfig->addIncludedDirectory(path);
3471 else
3472 gLibraryConfig->addExcludedDirectory(path);
3473 return errNone;
3476 static int prLanguageConfig_addIncludePath(struct VMGlobals * g, int numArgsPushed)
3478 return prLanguageConfig_addLibraryPath(g, numArgsPushed, includePaths);
3481 static int prLanguageConfig_addExcludePath(struct VMGlobals * g, int numArgsPushed)
3483 return prLanguageConfig_addLibraryPath(g, numArgsPushed, excludePaths);
3486 static int prLanguageConfig_removeLibraryPath(struct VMGlobals * g, int numArgsPushed, int pathType)
3488 PyrSlot *result = g->sp - 1;
3489 PyrSlot *dirString = g->sp;
3491 char path[MAXPATHLEN];
3492 bool error = slotStrVal(dirString, path, MAXPATHLEN);
3493 if (error)
3494 return errWrongType;
3496 if (pathType == includePaths)
3497 gLibraryConfig->removeIncludedDirectory(path);
3498 else
3499 gLibraryConfig->removeExcludedDirectory(path);
3500 return errNone;
3503 static int prLanguageConfig_removeIncludePath(struct VMGlobals * g, int numArgsPushed)
3505 return prLanguageConfig_removeLibraryPath(g, numArgsPushed, includePaths);
3508 static int prLanguageConfig_removeExcludePath(struct VMGlobals * g, int numArgsPushed)
3510 return prLanguageConfig_removeLibraryPath(g, numArgsPushed, excludePaths);
3513 static int prLanguageConfig_writeConfigFile(struct VMGlobals * g, int numArgsPushed)
3515 PyrSlot *result = g->sp - 1;
3516 PyrSlot *fileString = g->sp;
3518 char path[MAXPATHLEN];
3519 if (NotNil(fileString)) {
3520 bool error = slotStrVal(fileString, path, MAXPATHLEN);
3521 if (error)
3522 return errWrongType;
3523 } else {
3524 sc_GetUserConfigDirectory(path, PATH_MAX);
3525 sc_AppendToPath(path, MAXPATHLEN, "sclang_conf.yaml");
3528 gLibraryConfig->writeLibraryConfigYAML(path);
3529 return errNone;
3532 extern bool gPostInlineWarnings;
3533 static int prLanguageConfig_getPostInlineWarnings(struct VMGlobals * g, int numArgsPushed)
3535 PyrSlot *result = g->sp;
3536 SetBool(result, gPostInlineWarnings);
3537 return errNone;
3540 static int prLanguageConfig_setPostInlineWarnings(struct VMGlobals * g, int numArgsPushed)
3542 PyrSlot *result = g->sp - 1;
3543 PyrSlot *arg = g->sp;
3545 if (IsTrue(arg))
3546 gPostInlineWarnings = true;
3547 else if (IsFalse(arg))
3548 gPostInlineWarnings = false;
3549 else
3550 return errWrongType;
3552 return errNone;
3556 #define PRIMGROWSIZE 480
3557 PrimitiveTable gPrimitiveTable;
3559 void initPrimitiveTable()
3561 int i;
3562 gPrimitiveTable.maxsize = PRIMGROWSIZE;
3563 gPrimitiveTable.size = 0;
3564 // pyrmalloc:
3565 // lifetime: runtime. primitives are reloaded when library is compiled.
3566 gPrimitiveTable.table = (PrimitiveDef*)pyr_pool_runtime->Alloc(gPrimitiveTable.maxsize * sizeof(PrimitiveDef));
3567 MEMFAIL(gPrimitiveTable.table);
3568 for (i=0; i<gPrimitiveTable.maxsize; ++i) {
3569 gPrimitiveTable.table[i].func = undefinedPrimitive;
3570 gPrimitiveTable.table[i].name = s_none;
3571 gPrimitiveTable.table[i].base = 0;
3572 gPrimitiveTable.table[i].numArgs = 0;
3573 gPrimitiveTable.table[i].varArgs = 0;
3574 gPrimitiveTable.table[i].keyArgs = 0;
3578 void growPrimitiveTable(int newsize)
3580 PrimitiveDef *oldtable;
3581 int i, oldsize;
3582 //postfl("growPrimitiveTable %d %d\n", oldsize, newsize);
3583 oldtable = gPrimitiveTable.table;
3584 oldsize = gPrimitiveTable.maxsize;
3585 gPrimitiveTable.maxsize = newsize;
3586 // pyrmalloc:
3587 // lifetime: runtime. primitives are reloaded when library is compiled.
3588 gPrimitiveTable.table = (PrimitiveDef*)pyr_pool_runtime->Alloc(gPrimitiveTable.maxsize * sizeof(PrimitiveDef));
3589 MEMFAIL(gPrimitiveTable.table);
3590 memcpy(gPrimitiveTable.table, oldtable, oldsize * sizeof(PrimitiveDef));
3591 for (i=oldsize; i<gPrimitiveTable.maxsize; ++i) {
3592 gPrimitiveTable.table[i].func = undefinedPrimitive;
3593 gPrimitiveTable.table[i].name = s_none;
3594 gPrimitiveTable.table[i].base = 0;
3595 gPrimitiveTable.table[i].numArgs = 0;
3596 gPrimitiveTable.table[i].varArgs = 0;
3597 gPrimitiveTable.table[i].keyArgs = 0;
3599 pyr_pool_runtime->Free(oldtable);
3602 int definePrimitive(int base, int index, const char *name, PrimitiveHandler handler,
3603 int numArgs, int varArgs)
3605 int tableIndex;
3606 PyrSymbol *sym;
3608 if (name[0] != '_') {
3609 error("*** Primitive Name must begin with an underscore ***\n");
3610 postfl("name: '%s' index: %d\n", name, index);
3611 return -1;
3613 tableIndex = base + index;
3614 if (tableIndex < 0) {
3615 error("*** Negative Primitive Index ***\n");
3616 postfl("name: '%s' index: %d\n", name, tableIndex);
3617 return -1;
3619 if (tableIndex >= gPrimitiveTable.maxsize) {
3620 growPrimitiveTable(tableIndex + PRIMGROWSIZE);
3622 if (gPrimitiveTable.table[tableIndex].func != undefinedPrimitive) {
3623 error("*** Duplicate Primitive Index ***\n");
3624 postfl("name: '%s' index: %d\n", name, tableIndex);
3625 return -1;
3627 sym = getsym(name);
3628 gPrimitiveTable.table[tableIndex].func = handler;
3629 gPrimitiveTable.table[tableIndex].name = sym;
3630 gPrimitiveTable.table[tableIndex].base = base;
3631 gPrimitiveTable.table[tableIndex].numArgs = numArgs;
3632 gPrimitiveTable.table[tableIndex].varArgs = varArgs;
3633 gPrimitiveTable.table[tableIndex].keyArgs = 0;
3634 if (tableIndex > gPrimitiveTable.size) gPrimitiveTable.size = tableIndex;
3635 sym->u.index = tableIndex;
3636 return tableIndex;
3639 int definePrimitiveWithKeys(int base, int index, const char *name,
3640 PrimitiveHandler handler, PrimitiveWithKeysHandler keyhandler,
3641 int numArgs, int varArgs)
3643 int tableIndex;
3644 PyrSymbol *sym;
3646 if (name[0] != '_') {
3647 error("*** Primitive Name must begin with an underscore ***\n");
3648 postfl("name: '%s' index: %d\n", name, index);
3649 return -1;
3651 tableIndex = base + index;
3652 if (tableIndex < 0) {
3653 error("*** Negative Primitive Index ***\n");
3654 postfl("name: '%s' index: %d\n", name, tableIndex);
3655 return -1;
3657 if (tableIndex+1 >= gPrimitiveTable.maxsize) {
3658 growPrimitiveTable(tableIndex + PRIMGROWSIZE);
3660 if (gPrimitiveTable.table[tableIndex].func != undefinedPrimitive) {
3661 error("*** Duplicate Primitive Index ***\n");
3662 postfl("name: '%s' index: %d\n", name, tableIndex);
3663 return -1;
3665 sym = getsym(name);
3666 gPrimitiveTable.table[tableIndex].func = handler;
3667 gPrimitiveTable.table[tableIndex].name = sym;
3668 gPrimitiveTable.table[tableIndex].base = base;
3669 gPrimitiveTable.table[tableIndex].numArgs = numArgs;
3670 gPrimitiveTable.table[tableIndex].varArgs = varArgs;
3671 gPrimitiveTable.table[tableIndex].keyArgs = 1;
3672 sym->u.index = tableIndex;
3674 tableIndex++;
3675 gPrimitiveTable.table[tableIndex].func = (PrimitiveHandler)keyhandler;
3676 gPrimitiveTable.table[tableIndex].name = sym;
3677 gPrimitiveTable.table[tableIndex].base = base;
3678 gPrimitiveTable.table[tableIndex].numArgs = numArgs;
3679 gPrimitiveTable.table[tableIndex].varArgs = varArgs;
3680 gPrimitiveTable.table[tableIndex].keyArgs = 1;
3681 if (tableIndex > gPrimitiveTable.size) gPrimitiveTable.size = tableIndex;
3682 return tableIndex;
3685 int nextPrimitiveIndex()
3687 return gPrimitiveTable.size + 1;
3691 void doPrimitive(VMGlobals* g, PyrMethod* meth, int numArgsPushed)
3695 #ifdef GC_SANITYCHECK
3696 g->gc->SanityCheck();
3697 #endif
3699 //post("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3701 PyrMethodRaw *methraw = METHRAW(meth);
3702 int primIndex = methraw->specialIndex;
3704 PrimitiveDef *def = gPrimitiveTable.table + primIndex;
3705 int numArgsNeeded = def->numArgs;
3706 int diff = numArgsNeeded - numArgsPushed;
3708 if (diff != 0) { // incorrect num of args
3709 if (diff > 0) { // not enough args
3710 PyrSlot* pslot = g->sp;
3711 PyrSlot* qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
3712 for (int m=0; m<diff; ++m) slotCopy(++pslot, ++qslot);
3714 g->sp += diff;
3715 } else if (def->varArgs) { // has var args
3716 numArgsNeeded = numArgsPushed;
3717 } else {
3718 g->sp += diff; // remove excess args
3721 g->numpop = numArgsNeeded - 1;
3722 g->primitiveIndex = primIndex - def->base;
3723 g->primitiveMethod = meth;
3724 g->args = g->sp - numArgsNeeded;
3725 int err;
3726 try {
3727 #ifdef GC_SANITYCHECK
3728 g->gc->SanityCheck();
3729 #endif
3730 err = (*def->func)(g, numArgsNeeded);
3731 #ifdef GC_SANITYCHECK
3732 g->gc->SanityCheck();
3733 #endif
3734 } catch (std::exception& ex) {
3735 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3736 error(ex.what());
3737 err = errException;
3738 } catch (...) {
3739 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3740 err = errException;
3742 if (err <= errNone) g->sp -= g->numpop;
3743 else {
3744 //post("primitive failed %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3745 SetInt(&g->thread->primitiveIndex, methraw->specialIndex);
3746 SetInt(&g->thread->primitiveError, err);
3747 executeMethod(g, meth, numArgsNeeded);
3749 #ifdef GC_SANITYCHECK
3750 g->gc->SanityCheck();
3751 #endif
3754 void doPrimitiveWithKeys(VMGlobals* g, PyrMethod* meth, int allArgsPushed, int numKeyArgsPushed)
3756 int i, j, m, diff, err;
3757 PyrSlot *pslot, *qslot;
3758 int numArgsNeeded, numArgsPushed;
3760 #ifdef GC_SANITYCHECK
3761 g->gc->SanityCheck();
3762 #endif
3763 //post("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3764 //printf("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3766 PyrMethodRaw *methraw = METHRAW(meth);
3767 int primIndex = methraw->specialIndex;
3768 PrimitiveDef *def = gPrimitiveTable.table + primIndex;
3769 g->primitiveIndex = primIndex - def->base;
3770 g->primitiveMethod = meth;
3772 if (def->keyArgs && numKeyArgsPushed) {
3773 g->numpop = allArgsPushed - 1;
3774 try {
3775 err = ((PrimitiveWithKeysHandler)def[1].func)(g, allArgsPushed, numKeyArgsPushed);
3776 } catch (std::exception& ex) {
3777 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3778 error(ex.what());
3779 err = errException;
3780 } catch (...) {
3781 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3782 err = errException;
3784 if (err <= errNone) g->sp -= g->numpop;
3785 else {
3786 //post("primerr %d\n", err);
3787 SetInt(&g->thread->primitiveIndex, methraw->specialIndex);
3788 SetInt(&g->thread->primitiveError, err);
3789 executeMethodWithKeys(g, meth, allArgsPushed, numKeyArgsPushed);
3791 } else {
3792 numArgsNeeded = def->numArgs;
3793 numArgsPushed = allArgsPushed - (numKeyArgsPushed << 1);
3795 if (numKeyArgsPushed) {
3796 // evacuate keyword args to separate area
3797 pslot = keywordstack + (numKeyArgsPushed<<1);
3798 qslot = g->sp + 1;
3799 for (m=0; m<numKeyArgsPushed; ++m) {
3800 slotCopy(--pslot, --qslot);
3801 slotCopy(--pslot, --qslot);
3805 diff = numArgsNeeded - numArgsPushed;
3806 if (diff != 0) { // incorrect num of args
3807 if (diff > 0) { // not enough args
3808 g->sp += numArgsNeeded - allArgsPushed; // remove excess args
3809 pslot = g->sp - diff;
3810 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
3811 for (m=0; m<diff; ++m) slotCopy(++pslot, ++qslot);
3812 } else if (def->varArgs) { // has var args
3813 numArgsNeeded = numArgsPushed;
3814 g->sp += numArgsNeeded - allArgsPushed; // remove excess args
3815 } else {
3816 g->sp += numArgsNeeded - allArgsPushed; // remove excess args
3820 // do keyword lookup:
3821 if (numKeyArgsPushed && methraw->posargs) {
3822 PyrSymbol **name0, **name;
3823 PyrSlot *key, *vars;
3824 name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1;
3825 key = keywordstack;
3826 vars = g->sp - numArgsNeeded + 1;
3827 for (i=0; i<numKeyArgsPushed; ++i, key+=2) {
3828 name = name0;
3829 for (j=1; j<methraw->posargs; ++j, ++name) {
3830 if (*name == slotRawSymbol(key)) {
3831 slotCopy(&vars[j],&key[1]);
3832 goto found;
3835 if (gKeywordError) {
3836 post("WARNING: keyword arg '%s' not found in call to %s:%s\n",
3837 slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3839 found: ;
3842 g->numpop = numArgsNeeded - 1;
3843 try {
3844 err = (*def->func)(g, numArgsNeeded);
3845 } catch (std::exception& ex) {
3846 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3847 error(ex.what());
3848 err = errException;
3849 } catch (...) {
3850 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3851 err = errException;
3853 if (err <= errNone) g->sp -= g->numpop;
3854 else {
3855 //post("primerr %d\n", err);
3856 SetInt(&g->thread->primitiveIndex, methraw->specialIndex);
3857 SetInt(&g->thread->primitiveError, err);
3858 executeMethod(g, meth, numArgsNeeded);
3861 #ifdef GC_SANITYCHECK
3862 g->gc->SanityCheck();
3863 #endif
3866 void initPrimitives()
3868 int base, index;
3870 initPrimitiveTable();
3872 // unary operators
3873 base = nextPrimitiveIndex();
3874 definePrimitive(base, opNeg, "_Neg", doSpecialUnaryArithMsg, 1, 0);
3875 definePrimitive(base, opBitNot, "_BitNot", doSpecialUnaryArithMsg, 1, 0);
3876 definePrimitive(base, opAbs, "_Abs", doSpecialUnaryArithMsg, 1, 0);
3877 definePrimitive(base, opAsFloat, "_AsFloat", doSpecialUnaryArithMsg, 1, 0);
3878 definePrimitive(base, opAsInt, "_AsInt", doSpecialUnaryArithMsg, 1, 0);
3879 definePrimitive(base, opCeil, "_Ceil", doSpecialUnaryArithMsg, 1, 0); // 5
3880 definePrimitive(base, opFloor, "_Floor", doSpecialUnaryArithMsg, 1, 0);
3881 definePrimitive(base, opFrac, "_Frac", doSpecialUnaryArithMsg, 1, 0);
3882 definePrimitive(base, opSign, "_Sign", doSpecialUnaryArithMsg, 1, 0);
3883 definePrimitive(base, opSquared, "_Squared", doSpecialUnaryArithMsg, 1, 0);
3884 definePrimitive(base, opCubed, "_Cubed", doSpecialUnaryArithMsg, 1, 0); //10
3885 definePrimitive(base, opSqrt, "_Sqrt", doSpecialUnaryArithMsg, 1, 0);
3886 definePrimitive(base, opExp, "_Exp", doSpecialUnaryArithMsg, 1, 0);
3887 definePrimitive(base, opRecip, "_Recip", doSpecialUnaryArithMsg, 1, 0);
3888 definePrimitive(base, opMIDICPS, "_MIDICPS", doSpecialUnaryArithMsg, 1, 0);
3889 definePrimitive(base, opCPSMIDI, "_CPSMIDI", doSpecialUnaryArithMsg, 1, 0); //15
3891 definePrimitive(base, opMIDIRatio, "_MIDIRatio", doSpecialUnaryArithMsg, 1, 0);
3892 definePrimitive(base, opRatioMIDI, "_RatioMIDI", doSpecialUnaryArithMsg, 1, 0);
3893 definePrimitive(base, opDbAmp, "_DbAmp", doSpecialUnaryArithMsg, 1, 0);
3894 definePrimitive(base, opAmpDb, "_AmpDb", doSpecialUnaryArithMsg, 1, 0);
3895 definePrimitive(base, opOctCPS, "_OctCPS", doSpecialUnaryArithMsg, 1, 0);
3896 definePrimitive(base, opCPSOct, "_CPSOct", doSpecialUnaryArithMsg, 1, 0);
3897 definePrimitive(base, opLog, "_Log", doSpecialUnaryArithMsg, 1, 0);
3898 definePrimitive(base, opLog2, "_Log2", doSpecialUnaryArithMsg, 1, 0);
3899 definePrimitive(base, opLog10, "_Log10", doSpecialUnaryArithMsg, 1, 0);
3900 definePrimitive(base, opSin, "_Sin", doSpecialUnaryArithMsg, 1, 0);
3901 definePrimitive(base, opCos, "_Cos", doSpecialUnaryArithMsg, 1, 0);
3902 definePrimitive(base, opTan, "_Tan", doSpecialUnaryArithMsg, 1, 0);
3903 definePrimitive(base, opArcSin, "_ArcSin", doSpecialUnaryArithMsg, 1, 0);
3904 definePrimitive(base, opArcCos, "_ArcCos", doSpecialUnaryArithMsg, 1, 0);
3905 definePrimitive(base, opArcTan, "_ArcTan", doSpecialUnaryArithMsg, 1, 0);
3906 definePrimitive(base, opSinH, "_SinH", doSpecialUnaryArithMsg, 1, 0);
3907 definePrimitive(base, opCosH, "_CosH", doSpecialUnaryArithMsg, 1, 0);
3908 definePrimitive(base, opTanH, "_TanH", doSpecialUnaryArithMsg, 1, 0);
3909 definePrimitive(base, opRand, "_Rand", doSpecialUnaryArithMsg, 1, 0);
3910 definePrimitive(base, opRand2, "_Rand2", doSpecialUnaryArithMsg, 1, 0);
3911 definePrimitive(base, opLinRand, "_LinRand", doSpecialUnaryArithMsg, 1, 0);
3912 definePrimitive(base, opBiLinRand, "_BiLinRand", doSpecialUnaryArithMsg, 1, 0);
3914 definePrimitive(base, opSum3Rand, "_Sum3Rand", doSpecialUnaryArithMsg, 1, 0);
3915 // definePrimitive(base, opExpRand, "_ExpRand", doSpecialUnaryArithMsg, 1, 0);
3916 // definePrimitive(base, opBiExpRand, "_BiExpRand", doSpecialUnaryArithMsg, 1, 0);
3917 // definePrimitive(base, opGammaRand, "_GammaRand", doSpecialUnaryArithMsg, 1, 0);
3918 // definePrimitive(base, opGaussRand, "_GaussRand", doSpecialUnaryArithMsg, 1, 0);
3919 // definePrimitive(base, opPoiRand, "_PoiRand", doSpecialUnaryArithMsg, 1, 0);
3921 definePrimitive(base, opDistort, "_Distort", doSpecialUnaryArithMsg, 1, 0);
3922 definePrimitive(base, opSoftClip, "_SoftClip", doSpecialUnaryArithMsg, 1, 0);
3923 definePrimitive(base, opCoin, "_Coin", doSpecialUnaryArithMsg, 1, 0);
3925 definePrimitive(base, opRectWindow, "_RectWindow", doSpecialUnaryArithMsg, 1, 0);
3926 definePrimitive(base, opHanWindow, "_HanWindow", doSpecialUnaryArithMsg, 1, 0);
3927 definePrimitive(base, opWelchWindow, "_WelchWindow", doSpecialUnaryArithMsg, 1, 0);
3928 definePrimitive(base, opTriWindow, "_TriWindow", doSpecialUnaryArithMsg, 1, 0);
3930 definePrimitive(base, opSCurve, "_SCurve", doSpecialUnaryArithMsg, 1, 0);
3931 definePrimitive(base, opRamp, "_Ramp", doSpecialUnaryArithMsg, 1, 0);
3933 definePrimitive(base, opDigitValue, "_DigitValue", doSpecialUnaryArithMsg, 1, 0);
3936 // binary operators
3937 base = nextPrimitiveIndex();
3938 definePrimitive(base, opAdd, "_Add", prAddNum, 2, 0);
3939 definePrimitive(base, opSub, "_Sub", prSubNum, 2, 0);
3940 definePrimitive(base, opMul, "_Mul", prMulNum, 2, 0);
3942 definePrimitive(base, opIDiv, "_IDiv", prSpecialBinaryArithMsg, 3, 0);
3943 definePrimitive(base, opFDiv, "_FDiv", prSpecialBinaryArithMsg, 3, 0);
3944 definePrimitive(base, opMod, "_Mod", prSpecialBinaryArithMsg, 3, 0);
3945 definePrimitive(base, opEQ, "_EQ", prSpecialBinaryArithMsg, 3, 0);
3946 definePrimitive(base, opNE, "_NE", prSpecialBinaryArithMsg, 3, 0);
3947 definePrimitive(base, opLT, "_LT", prSpecialBinaryArithMsg, 3, 0);
3948 definePrimitive(base, opGT, "_GT", prSpecialBinaryArithMsg, 3, 0);
3949 definePrimitive(base, opLE, "_LE", prSpecialBinaryArithMsg, 3, 0);
3950 definePrimitive(base, opGE, "_GE", prSpecialBinaryArithMsg, 3, 0);
3951 //definePrimitive(base, opIdentical, "_Identical", prSpecialBinaryArithMsg, 3, 0);
3952 //definePrimitive(base, opNotIdentical, "_NotIdentical", prSpecialBinaryArithMsg, 3, 0);
3954 definePrimitive(base, opMin, "_Min", prSpecialBinaryArithMsg, 3, 0);
3955 definePrimitive(base, opMax, "_Max", prSpecialBinaryArithMsg, 3, 0);
3956 definePrimitive(base, opBitAnd, "_BitAnd", prSpecialBinaryArithMsg, 3, 0);
3957 definePrimitive(base, opBitOr, "_BitOr", prSpecialBinaryArithMsg, 3, 0);
3958 definePrimitive(base, opBitXor, "_BitXor", prSpecialBinaryArithMsg, 3, 0);
3959 definePrimitive(base, opLCM, "_LCM", prSpecialBinaryArithMsg, 3, 0);
3960 definePrimitive(base, opGCD, "_GCD", prSpecialBinaryArithMsg, 3, 0);
3961 definePrimitive(base, opRound, "_Round", prSpecialBinaryArithMsg, 3, 0);
3962 definePrimitive(base, opRoundUp, "_RoundUp", prSpecialBinaryArithMsg, 3, 0);
3963 definePrimitive(base, opTrunc, "_Trunc", prSpecialBinaryArithMsg, 3, 0);
3964 definePrimitive(base, opAtan2, "_Atan2", prSpecialBinaryArithMsg, 3, 0);
3965 definePrimitive(base, opHypot, "_Hypot", prSpecialBinaryArithMsg, 3, 0);
3966 definePrimitive(base, opHypotx, "_HypotApx", prSpecialBinaryArithMsg, 3, 0);
3967 definePrimitive(base, opPow, "_Pow", prSpecialBinaryArithMsg, 3, 0);
3968 definePrimitive(base, opShiftLeft, "_ShiftLeft", prSpecialBinaryArithMsg, 3, 0);
3969 definePrimitive(base, opShiftRight, "_ShiftRight", prSpecialBinaryArithMsg, 3, 0);
3970 definePrimitive(base, opUnsignedShift, "_UnsignedShift", prSpecialBinaryArithMsg, 3, 0);
3971 definePrimitive(base, opFill, "_Fill", prSpecialBinaryArithMsg, 3, 0);
3972 definePrimitive(base, opRing1, "_Ring1", prSpecialBinaryArithMsg, 3, 0); // a * (b + 1) == a * b + a
3973 definePrimitive(base, opRing2, "_Ring2", prSpecialBinaryArithMsg, 3, 0); // a * b + a + b
3974 definePrimitive(base, opRing3, "_Ring3", prSpecialBinaryArithMsg, 3, 0); // a*a*b
3975 definePrimitive(base, opRing4, "_Ring4", prSpecialBinaryArithMsg, 3, 0); // a*a*b - a*b*b
3976 definePrimitive(base, opDifSqr, "_DifSqr", prSpecialBinaryArithMsg, 3, 0); // a*a - b*b
3977 definePrimitive(base, opSumSqr, "_SumSqr", prSpecialBinaryArithMsg, 3, 0); // a*a + b*b
3978 definePrimitive(base, opSqrSum, "_SqrSum", prSpecialBinaryArithMsg, 3, 0); // (a + b)^2
3979 definePrimitive(base, opSqrDif, "_SqrDif", prSpecialBinaryArithMsg, 3, 0); // (a - b)^2
3980 definePrimitive(base, opAbsDif, "_AbsDif", prSpecialBinaryArithMsg, 3, 0); // abs(a - b)
3981 definePrimitive(base, opThresh, "_Thresh", prSpecialBinaryArithMsg, 3, 0); // a * max(0,b)
3982 definePrimitive(base, opAMClip, "_AMClip", prSpecialBinaryArithMsg, 3, 0); // a * max(0,b)
3983 definePrimitive(base, opScaleNeg, "_ScaleNeg", prSpecialBinaryArithMsg, 3, 0); // a < 0 ? a*b : a
3984 definePrimitive(base, opClip2, "_Clip2", prSpecialBinaryArithMsg, 3, 0);
3985 definePrimitive(base, opFold2, "_Fold2", prSpecialBinaryArithMsg, 3, 0);
3986 definePrimitive(base, opWrap2, "_Wrap2", prSpecialBinaryArithMsg, 3, 0);
3987 definePrimitive(base, opExcess, "_Excess", prSpecialBinaryArithMsg, 3, 0);
3988 definePrimitive(base, opFirstArg, "_FirstArg", prSpecialBinaryArithMsg, 3, 0);
3989 definePrimitive(base, opRandRange, "_RandRange", prSpecialBinaryArithMsg, 3, 0);
3990 definePrimitive(base, opExpRandRange, "_ExpRandRange", prSpecialBinaryArithMsg, 3, 0);
3992 // general primitives
3993 base = nextPrimitiveIndex();
3994 index = 0;
3995 definePrimitive(base, index++, "_Halt", haltInterpreter, 1, 0);
3996 definePrimitive(base, index++, "_InstVarAt", instVarAt, 2, 0);
3997 definePrimitive(base, index++, "_InstVarPut", instVarPut, 3, 0);
3998 definePrimitive(base, index++, "_InstVarSize", instVarSize, 1, 0);
3999 definePrimitive(base, index++, "_ObjectHash", objectHash, 1, 0);
4000 definePrimitive(base, index++, "_ObjectClass", objectClass, 1, 0);
4001 definePrimitive(base, index++, "_BasicNew", basicNew, 2, 0);
4002 definePrimitive(base, index++, "_BasicNewClear", basicNewClear, 2, 0);
4003 definePrimitive(base, index++, "_BasicNewCopyArgsToInstVars", basicNewCopyArgsToInstanceVars, 1, 1);
4004 //definePrimitive(base, index++, "_BasicNewCopyArgsByName", basicNewCopyArgsByName, 1, 1);
4006 definePrimitiveWithKeys(base, index, "_FunctionValue", blockValue, blockValueWithKeys, 1, 1);
4007 index+=2;
4008 definePrimitiveWithKeys(base, index, "_FunctionValueEnvir", blockValueEnvir, blockValueEnvirWithKeys, 1, 1);
4009 index+=2;
4011 definePrimitive(base, index++, "_FunctionValueArray", blockValueArray, 1, 1);
4012 definePrimitive(base, index++, "_FunctionValueArrayEnvir", blockValueArrayEnvir, 1, 1);
4013 definePrimitive(base, index++, "_FunctionDefAsFunction", prFunctionDefAsFunction, 1, 0);
4014 definePrimitive(base, index++, "_FunctionDefDumpContexts", prFunctionDefDumpContexts, 1, 0);
4015 definePrimitive(base, index++, "_FunctionDefIsClosed", prFunctionDefIsClosed, 1, 0);
4016 definePrimitive(base, index++, "_FunctionDefIsWithinClosed", prFunctionDefIsWithinClosed, 1, 0);
4018 definePrimitive(base, index++, "_ObjectIsKindOf", objectIsKindOf, 2, 0);
4019 definePrimitive(base, index++, "_ObjectIsMemberOf", objectIsMemberOf, 2, 0);
4020 definePrimitive(base, index++, "_ObjectDump", objectDump, 1, 0);
4021 definePrimitive(base, index++, "_TotalFree", prTotalFree, 1, 0);
4022 definePrimitive(base, index++, "_LargestFreeBlock", prLargestFreeBlock, 1, 0);
4024 definePrimitive(base, index++, "_GCInfo", dumpGCinfo, 1, 0);
4025 definePrimitive(base, index++, "_GCDumpGrey", dumpGCdumpGrey, 1, 0);
4026 definePrimitive(base, index++, "_GCDumpSet", dumpGCdumpSet, 2, 0);
4027 definePrimitive(base, index++, "_GCSanity", prGCSanity, 1, 0);
4028 #if GCDEBUG
4029 definePrimitive(base, index++, "_TraceAllPathsTo", prTraceAllPathsTo, 1, 0);
4030 definePrimitive(base, index++, "_TraceAnyPathsTo", prTraceAnyPathsTo, 1, 0);
4031 definePrimitive(base, index++, "_TraceAnyPathToAllInstancesOf", prTraceAnyPathToAllInstancesOf, 1, 0);
4032 #endif
4034 definePrimitive(base, index++, "_Identical", objectIdentical, 2, 0);
4035 definePrimitive(base, index++, "_NotIdentical", objectNotIdentical, 2, 0);
4036 definePrimitiveWithKeys(base, index, "_ObjectPerform", objectPerform, objectPerformWithKeys, 2, 1);
4037 index+=2;
4038 definePrimitive(base, index++, "_ObjectPerformList", objectPerformList, 2, 1);
4039 definePrimitiveWithKeys(base, index, "_SuperPerform", objectSuperPerform, objectSuperPerformWithKeys, 2, 1);
4040 index+=2;
4041 definePrimitive(base, index++, "_SuperPerformList", objectSuperPerformList, 2, 1);
4042 definePrimitive(base, index++, "_ObjectPerformMsg", objectPerformSelList, 2, 0);
4043 //definePrimitive(base, index++, "_ArrayPerformMsg", arrayPerformMsg, 1, 1);
4044 definePrimitive(base, index++, "_ObjectString", prObjectString, 1, 0);
4045 definePrimitive(base, index++, "_Float_AsStringPrec", prFloat_AsStringPrec, 2, 0);
4046 definePrimitive(base, index++, "_ObjectCompileString", prAsCompileString, 1, 0);
4047 definePrimitive(base, index++, "_ClassString", prClassString, 1, 0);
4048 definePrimitive(base, index++, "_PostString", prPostString, 1, 0);
4049 definePrimitive(base, index++, "_PostLine", prPostLine, 1, 0);
4050 definePrimitive(base, index++, "_HostDebugger", prDebugger, 1, 0);
4051 definePrimitive(base, index++, "_Trace", prTraceOn, 1, 0);
4052 definePrimitive(base, index++, "_CanCallOS", prCanCallOS, 1, 0);
4053 definePrimitive(base, index++, "_KeywordError", prKeywordError, 1, 0);
4054 definePrimitive(base, index++, "_GetTailCallOptimize", prGetTailCallOptimize, 1, 0);
4055 definePrimitive(base, index++, "_SetTailCallOptimize", prSetTailCallOptimize, 2, 0);
4058 definePrimitive(base, index++, "_PrimitiveError", prPrimitiveError, 1, 0);
4059 definePrimitive(base, index++, "_PrimitiveErrorString", prPrimitiveErrorString, 1, 0);
4060 definePrimitive(base, index++, "_DumpStack", prDumpStack, 1, 0);
4061 definePrimitive(base, index++, "_DumpDetailedBackTrace", prDumpDetailedBackTrace, 1, 0);
4062 definePrimitive(base, index++, "_StackDepth", prStackDepth, 1, 0);
4063 definePrimitive(base, index++, "_PrimName", prPrimName, 1, 0);
4064 definePrimitive(base, index++, "_ObjectShallowCopy", prObjectShallowCopy, 1, 0);
4065 definePrimitive(base, index++, "_ObjectCopyImmutable", prObjectCopyImmutable, 1, 0);
4066 definePrimitive(base, index++, "_ObjectCopyRange", prObjectCopyRange, 3, 0);
4067 definePrimitive(base, index++, "_ObjectCopySeries", prObjectCopySeries, 4, 0);
4068 definePrimitive(base, index++, "_ObjectPointsTo", prObjectPointsTo, 2, 0);
4069 definePrimitive(base, index++, "_ObjectRespondsTo", prObjectRespondsTo, 2, 0);
4070 definePrimitive(base, index++, "_ObjectIsMutable", prObjectIsMutable, 1, 0);
4071 definePrimitive(base, index++, "_ObjectIsPermanent", prObjectIsPermanent, 1, 0);
4072 definePrimitive(base, index++, "_ObjectDeepFreeze", prDeepFreeze, 1, 0);
4073 definePrimitive(base, index++, "_ObjectDeepCopy", prDeepCopy, 1, 0);
4075 #if !SCPLAYER
4076 definePrimitive(base, index++, "_CompileExpression", prCompileString, 2, 0);
4077 #endif
4078 definePrimitive(base, index++, "_GetBackTrace", prGetBackTrace, 1, 0);
4079 definePrimitive(base, index++, "_DumpBackTrace", prDumpBackTrace, 1, 0);
4080 definePrimitive(base, index++, "_DumpByteCodes", prDumpByteCodes, 1, 0);
4082 definePrimitive(base, index++, "_AllClasses", prAllClasses, 1, 0);
4083 definePrimitive(base, index++, "_DumpClassSubtree", prPostClassTree, 1, 0);
4085 // definePrimitive(base, index++, "_TabletTracking", prTabletTracking, 1, 0);
4087 definePrimitive(base, index++, "_FunDef_NumArgs", prFunDef_NumArgs, 1, 0);
4088 definePrimitive(base, index++, "_FunDef_NumVars", prFunDef_NumVars, 1, 0);
4089 definePrimitive(base, index++, "_FunDef_VarArgs", prFunDef_VarArgs, 1, 0);
4091 definePrimitive(base, index++, "_Thread_Init", prThreadInit, 3, 0);
4092 definePrimitive(base, index++, "_Thread_RandSeed", prThreadRandSeed, 2, 0);
4093 definePrimitive(base, index++, "_Thread_GetRandData", prThreadGetRandData, 1, 0);
4094 definePrimitive(base, index++, "_Thread_SetRandData", prThreadSetRandData, 2, 0);
4095 // definePrimitive(base, index++, "_ThreadRun", prThreadRun, 2, 0);
4096 // definePrimitive(base, index++, "_RunNextThread", prRunNextThread, 1, 0);
4097 definePrimitive(base, index++, "_RoutineYield", prRoutineYield, 1, 0);
4098 definePrimitive(base, index++, "_RoutineAlwaysYield", prRoutineAlwaysYield, 1, 0);
4099 definePrimitive(base, index++, "_RoutineResume", prRoutineResume, 2, 0);
4100 definePrimitive(base, index++, "_RoutineReset", prRoutineReset, 1, 0);
4101 definePrimitive(base, index++, "_RoutineYieldAndReset", prRoutineYieldAndReset, 2, 0);
4102 definePrimitive(base, index++, "_RoutineStop", prRoutineStop, 1, 0);
4104 // definePrimitive(base, index++, "_IsDemo", prIsDemo, 1, 0);
4105 definePrimitive(base, index++, "_Blork", prBlork, 1, 0);
4106 definePrimitive(base, index++, "_UGenCodeString", prUGenCodeString, 5, 0);
4107 definePrimitive(base, index++, "_MainOverwriteMsg", prOverwriteMsg, 1, 0);
4109 definePrimitive(base, index++, "_AppClock_SchedNotify", prAppClockSchedNotify, 1, 0);
4110 definePrimitive(base, index++, "_LanguageConfig_getIncludePaths", prLanguageConfig_getIncludePaths, 1, 0);
4111 definePrimitive(base, index++, "_LanguageConfig_getExcludePaths", prLanguageConfig_getExcludePaths, 1, 0);
4112 definePrimitive(base, index++, "_LanguageConfig_addIncludePath", prLanguageConfig_addIncludePath, 2, 0);
4113 definePrimitive(base, index++, "_LanguageConfig_addExcludePath", prLanguageConfig_addExcludePath, 2, 0);
4114 definePrimitive(base, index++, "_LanguageConfig_removeIncludePath", prLanguageConfig_removeIncludePath, 2, 0);
4115 definePrimitive(base, index++, "_LanguageConfig_removeExcludePath", prLanguageConfig_removeExcludePath, 2, 0);
4116 definePrimitive(base, index++, "_LanguageConfig_writeConfigFile", prLanguageConfig_writeConfigFile, 2, 0);
4117 definePrimitive(base, index++, "_LanguageConfig_getPostInlineWarnings", prLanguageConfig_getPostInlineWarnings, 1, 0);
4118 definePrimitive(base, index++, "_LanguageConfig_setPostInlineWarnings", prLanguageConfig_setPostInlineWarnings, 2, 0);
4120 //void initOscilPrimitives();
4121 //void initControllerPrimitives();
4123 //initOscilPrimitives();
4124 //initControllerPrimitives();
4125 initMathPrimitives();
4126 initSignalPrimitives();
4127 initArrayPrimitives();
4129 void initSymbolPrimitives();
4130 initSymbolPrimitives();
4132 void initArchiverPrimitives();
4133 initArchiverPrimitives();
4135 void initArrayPrimitives();
4136 initArrayPrimitives();
4138 void initBitPrimitives();
4139 initBitPrimitives();
4141 void initCharPrimitives();
4142 initCharPrimitives();
4144 void initFilePrimitives();
4145 initFilePrimitives();
4147 void initPlatformPrimitives();
4148 initPlatformPrimitives();
4150 void initStringPrimitives();
4151 initStringPrimitives();
4153 void initListPrimitives();
4154 initListPrimitives();
4157 void initUnixPrimitives();
4158 initUnixPrimitives();
4160 void init_OSC_primitives();
4161 init_OSC_primitives();
4163 /* these probably should be moved out of the Lang code
4164 into an App init primitives section */
4165 void initGUIPrimitives();
4166 initGUIPrimitives();
4168 void initSCViewPrimitives();
4169 initSCViewPrimitives();
4171 void initSchedPrimitives();
4172 initSchedPrimitives();
4174 #if (defined(__APPLE__) && !defined(SC_IPHONE)) || defined(HAVE_ALSA)
4175 void initMIDIPrimitives();
4176 initMIDIPrimitives();
4177 #endif
4179 #if !defined(SC_WIN32) && !defined(SC_IPHONE)
4180 void initHIDPrimitives();
4181 initHIDPrimitives();
4183 void initSpeechPrimitives();
4184 initSpeechPrimitives();
4186 void initCocoaFilePrimitives();
4187 initCocoaFilePrimitives();
4189 void initCocoaBridgePrimitives();
4190 initCocoaBridgePrimitives();
4192 void initSerialPrimitives();
4193 initSerialPrimitives();
4195 void initWiiPrimitives();
4196 initWiiPrimitives();
4198 #endif
4199 #ifdef SC_DARWIN
4200 void initCoreAudioPrimitives();
4201 initCoreAudioPrimitives();
4202 #endif
4204 // CR ADDED
4205 void initRendezvousPrimitives();
4206 initRendezvousPrimitives();
4208 #ifdef SCOGL_COMPILE
4209 void initOpenGLPrimitives();
4210 initOpenGLPrimitives();
4211 #endif
4213 #ifdef SC_QT
4214 QtCollider::initPrimitives();
4215 #endif
4217 s_recvmsg = getsym("receiveMsg");
4218 post("\tNumPrimitives = %d\n", nextPrimitiveIndex());
4223 void initThreads();
4224 void initThreads()
4226 s_prrunnextthread = getsym("prRunNextThread");
4227 s_prready = getsym("prReady");