scide: implement selectionLength for openDocument
[supercollider.git] / lang / LangPrimSource / PyrPrimitive.cpp
blobdf10e9a3d96ee438b9f2142d5bff7048b94d9c8a
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 #include "SCDocPrim.h"
64 int yyparse();
66 extern bool gTraceInterpreter;
67 PyrSymbol *s_recvmsg;
69 void initPatternPrimitives();
71 typedef struct {
72 PrimitiveHandler func;
73 PyrSymbol* name;
74 unsigned short base;
75 unsigned char numArgs;
76 unsigned char varArgs;
77 unsigned char keyArgs;
78 } PrimitiveDef;
80 typedef struct {
81 int size, maxsize;
82 PrimitiveDef *table;
83 } PrimitiveTable;
85 extern PrimitiveTable gPrimitiveTable;
87 extern PyrSlot o_nullframe;
90 int getPrimitiveNumArgs(int index)
92 return gPrimitiveTable.table[index].numArgs;
95 PyrSymbol* getPrimitiveName(int index)
97 return gPrimitiveTable.table[index].name;
100 int slotStrLen(PyrSlot *slot)
102 if (IsSym(slot))
103 return slotRawSymbol(slot)->length;
104 if (isKindOfSlot(slot, class_string))
105 return slotRawObject(slot)->size;
107 return -1;
110 int slotStrVal(PyrSlot *slot, char *str, int maxlen)
112 if (IsSym(slot)) {
113 strncpy(str, slotRawSymbol(slot)->name, maxlen);
114 return errNone;
115 } else if (isKindOfSlot(slot, class_string)) {
116 int len;
117 len = sc_min(maxlen-1, slotRawObject(slot)->size);
118 memcpy(str, slotRawString(slot)->s, len);
119 str[len] = 0;
120 return errNone;
122 return errWrongType;
125 int slotPStrVal(PyrSlot *slot, unsigned char *str)
127 if (IsSym(slot)) {
128 strncpy((char*)str+1, slotRawSymbol(slot)->name, 255);
129 str[0] = slotRawSymbol(slot)->length;
130 return errNone;
131 } else if (isKindOfSlot(slot, class_string)) {
132 int len;
133 len = sc_min(255, slotRawObject(slot)->size);
134 memcpy(str+1, slotRawString(slot)->s, len);
135 str[0] = len;
136 return errNone;
138 return errWrongType;
141 int instVarAt(struct VMGlobals *g, int numArgsPushed)
143 PyrSlot *a, *b;
144 int index;
146 a = g->sp - 1;
147 b = g->sp;
149 if (NotObj(a)) return errWrongType;
151 PyrObject *obj = slotRawObject(a);
153 if (IsInt(b)) {
154 index = slotRawInt(b);
155 if (index < 0 || index >= obj->size) return errIndexOutOfRange;
156 slotCopy(a,&obj->slots[index]);
157 } else if (IsSym(b)) {
158 PyrSlot *instVarNamesSlot = &obj->classptr->instVarNames;
159 if (!isKindOfSlot(instVarNamesSlot, class_symbolarray)) return errFailed;
160 PyrSymbolArray *instVarNames = slotRawSymbolArray(instVarNamesSlot);
161 PyrSymbol **names = instVarNames->symbols;
162 PyrSymbol *name = slotRawSymbol(b);
163 for (int i=0; i<instVarNames->size; ++i) {
164 if (names[i] == name) {
165 slotCopy(a,&obj->slots[i]);
166 return errNone;
169 return errFailed;
170 } else return errWrongType;
171 return errNone;
174 int instVarPut(struct VMGlobals *g, int numArgsPushed)
176 PyrSlot *a, *b, *c, *slot;
177 int index;
178 PyrObject *obj;
180 a = g->sp - 2;
181 b = g->sp - 1;
182 c = g->sp;
184 if (NotObj(a)) return errWrongType;
185 obj = slotRawObject(a);
186 if (obj->IsImmutable()) return errImmutableObject;
188 if (IsInt(b)) {
189 index = slotRawInt(b);
190 if (index < 0 || index >= obj->size) return errIndexOutOfRange;
191 slot = obj->slots + index;
192 slotCopy(slot,c);
193 g->gc->GCWrite(obj, slot);
194 } else if (IsSym(b)) {
195 PyrSlot *instVarNamesSlot = &obj->classptr->instVarNames;
196 if (!IsObj(instVarNamesSlot)) return errFailed;
197 PyrSymbolArray *instVarNames = slotRawSymbolArray(instVarNamesSlot);
198 PyrSymbol **names = instVarNames->symbols;
199 PyrSymbol *name = slotRawSymbol(b);
200 for (int i=0; i<instVarNames->size; ++i) {
201 if (names[i] == name) {
202 slot = obj->slots + i;
203 slotCopy(slot,c);
204 g->gc->GCWrite(obj, slot);
205 return errNone;
208 post("WARNING: %s instVarPut '%s' failed.\n", slotRawSymbol(&obj->classptr->name)->name, name->name);
209 return errNone;
210 } else return errWrongType;
211 return errNone;
214 int instVarSize(struct VMGlobals *g, int numArgsPushed)
216 PyrSlot *a;
217 PyrObject *obj;
219 a = g->sp;
220 if (NotObj(a)) {
221 SetInt(a, 0);
222 return errNone;
224 obj = slotRawObject(a);
225 if (obj->obj_format == obj_notindexed) {
226 SetInt(a, obj->size);
227 } else {
228 SetInt(a, 0);
230 return errNone;
234 int objectHash(struct VMGlobals *g, int numArgsPushed)
236 PyrSlot *a;
237 int hash;
239 a = g->sp;
241 hash = calcHash(a);
242 SetInt(a, hash);
243 return errNone;
246 int objectClass(struct VMGlobals *g, int numArgsPushed)
248 PyrSlot *a;
249 PyrClass *classobj;
251 a = g->sp;
252 classobj = classOfSlot(a);
253 SetObject(a, classobj);
254 return errNone;
257 int prPrimitiveError(struct VMGlobals *g, int numArgsPushed)
259 PyrSlot *a;
261 a = g->sp;
262 slotCopy(a,&g->thread->primitiveError);
263 return errNone;
266 int prStackDepth(struct VMGlobals *g, int numArgsPushed);
267 int prStackDepth(struct VMGlobals *g, int numArgsPushed)
269 PyrSlot *a;
271 a = g->sp;
272 SetInt(a, g->gc->StackDepth());
273 return errNone;
276 extern void DumpStack(VMGlobals *g, PyrSlot *sp);
278 int prDumpStack(struct VMGlobals *g, int numArgsPushed)
280 DumpStack(g, g->sp);
281 return errNone;
284 void DumpDetailedBackTrace(VMGlobals *g);
285 int prDumpDetailedBackTrace(struct VMGlobals *g, int numArgsPushed);
286 int prDumpDetailedBackTrace(struct VMGlobals *g, int numArgsPushed)
288 DumpDetailedBackTrace(g);
289 return errNone;
292 int prPrimitiveErrorString(struct VMGlobals *g, int numArgsPushed)
294 PyrSlot *a;
295 PyrString *string;
296 const char *str;
298 a = g->sp;
299 switch (slotRawInt(&g->thread->primitiveError)) {
300 case errReturn : str = "Return (not an error)."; break;
301 case errNone : str = "No Error"; break;
302 case errFailed : str = "Failed."; break;
303 case errBadPrimitive : str = "Bad Primitive."; break;
304 case errWrongType : str = "Wrong type."; break;
305 case errIndexNotAnInteger : str = "Index not an Integer"; break;
306 case errIndexOutOfRange : str = "Index out of range."; break;
307 case errImmutableObject : str = "Attempted write to immutable object."; break;
308 case errNotAnIndexableObject : str = "Not an indexable object."; break;
309 case errStackOverflow : str = "Stack overflow."; break;
310 case errOutOfMemory : str = "Out of memory."; break;
311 case errCantCallOS : str = "Operation cannot be called from this Process. Try using AppClock instead of SystemClock."; break;
313 default : str = "Failed.";
315 string = newPyrString(g->gc, str, 0, true);
316 SetObject(a, string);
317 return errNone;
322 int prPostString(struct VMGlobals *g, int numArgsPushed)
324 PyrSlot *a;
326 a = g->sp;
327 //if (NotObj(a)) return errWrongType;
328 // assume it is a string!
329 postText(slotRawString(a)->s, slotRawString(a)->size);
330 return errNone;
333 int prPostLine(struct VMGlobals *g, int numArgsPushed)
335 PyrSlot *a;
337 a = g->sp;
338 //if (NotObj(a)) return errWrongType;
339 // assume it is a string!
340 postText(slotRawString(a)->s, slotRawString(a)->size);
341 postChar('\n');
342 return errNone;
345 int prDebugger(struct VMGlobals *g, int numArgsPushed)
347 PyrSlot *a;
349 a = g->sp;
350 //Debugger();
351 return errNone;
357 int prObjectString(struct VMGlobals *g, int numArgsPushed)
359 PyrSlot *a;
360 PyrString *string;
361 char str[256];
363 a = g->sp;
364 if (IsSym(a)) {
365 string = newPyrString(g->gc, slotRawSymbol(a)->name, 0, true);
366 SetObject(a, string);
367 return errNone;
368 } else if (postString(a, str)) {
369 string = newPyrString(g->gc, str, 0, true);
370 SetObject(a, string);
371 return errNone;
372 } else {
373 return errFailed;
377 int prFloat_AsStringPrec(struct VMGlobals *g, int numArgsPushed);
378 int prFloat_AsStringPrec(struct VMGlobals *g, int numArgsPushed)
380 PyrSlot *a = g->sp - 1;
381 PyrSlot *b = g->sp;
383 int precision;
384 int err = slotIntVal(b, &precision);
385 if (err) return err;
387 char fmt[8], str[256];
388 sprintf(fmt, "%%.%dg", precision);
389 sprintf(str, fmt, slotRawFloat(a));
391 PyrString *string = newPyrString(g->gc, str, 0, true);
392 SetObject(a, string);
393 return errNone;
397 int prAsCompileString(struct VMGlobals *g, int numArgsPushed);
398 int prAsCompileString(struct VMGlobals *g, int numArgsPushed)
400 PyrSlot *a;
401 PyrString *string;
402 int err = errNone;
404 a = g->sp;
405 if (IsSym(a)) {
406 int len = strlen(slotRawSymbol(a)->name) + 1;
407 if (len < 255) {
408 char str[256];
409 sprintf(str, "'%s'", slotRawSymbol(a)->name);
410 string = newPyrString(g->gc, str, 0, true);
411 } else {
412 char *str = (char*)malloc(len+2);
413 sprintf(str, "'%s'", slotRawSymbol(a)->name);
414 string = newPyrString(g->gc, str, 0, true);
415 free(str);
417 } else {
418 char str[256];
419 err = asCompileString(a, str);
420 if (err) return err;
421 string = newPyrString(g->gc, str, 0, true);
423 SetObject(a, string);
424 return err;
428 int prClassString(struct VMGlobals *g, int numArgsPushed)
430 PyrSlot *a;
431 PyrClass *classobj;
432 PyrString *string;
434 a = g->sp;
435 classobj = classOfSlot(a);
436 string = newPyrString(g->gc, slotRawSymbol(&classobj->name)->name, 0, true);
437 SetObject(a, string);
438 return errNone;
442 int prPrimName(struct VMGlobals *g, int numArgsPushed)
444 PyrSlot *a;
445 PyrThread *thread;
447 a = g->sp;
448 thread = slotRawThread(a);
449 if (slotRawInt(&thread->primitiveIndex) <= gPrimitiveTable.size) {
450 SetSymbol(a, gPrimitiveTable.table[slotRawInt(&thread->primitiveIndex)].name);
451 } else {
452 SetSymbol(a, s_none);
454 return errNone;
457 int objectIsKindOf(struct VMGlobals *g, int numArgsPushed)
459 PyrSlot *a, *b;
460 PyrClass *classobj, *testclass;
461 int objClassIndex, testClassIndex, maxSubclassIndex;
463 a = g->sp - 1;
464 b = g->sp;
466 if (NotObj(b)) return errWrongType;
467 testclass = (PyrClass*)slotRawObject(b);
468 classobj = classOfSlot(a);
469 #if 0
470 while (classobj) {
471 if (classobj == testclass) {
472 SetTrue(a);
473 return errNone;
475 classobj = slotRawSymbol(&classobj->superclass)->u.classobj;
477 SetFalse(a);
478 #else
479 // constant time lookup method:
481 objClassIndex = slotRawInt(&classobj->classIndex);
482 testClassIndex = slotRawInt(&testclass->classIndex);
483 maxSubclassIndex = slotRawInt(&testclass->maxSubclassIndex);
485 /*post("%s %s\n", slotRawSymbol(&classobj->name)->name, testclass->name.us->name);
486 post("objClassIndex %d\n", objClassIndex);
487 post("testClassIndex %d\n", testClassIndex);
488 post("maxSubclassIndex %d\n", maxSubclassIndex);*/
490 if (objClassIndex >= testClassIndex && objClassIndex <= maxSubclassIndex) {
491 SetTrue(a);
492 return errNone;
493 } else {
494 SetFalse(a);
495 return errNone;
498 #endif
499 return errNone;
503 int objectIsMemberOf(struct VMGlobals *g, int numArgsPushed)
505 PyrSlot *a, *b;
506 PyrClass *classobj, *testclass;
508 a = g->sp - 1;
509 b = g->sp;
511 if (NotObj(b)) return errWrongType;
512 testclass = (PyrClass*)slotRawObject(b);
513 classobj = classOfSlot(a);
514 if (classobj == testclass) {
515 SetTrue(a);
516 } else {
517 SetFalse(a);
519 return errNone;
522 int objectIdentical(struct VMGlobals *g, int numArgsPushed)
524 PyrSlot *a, *b;
526 a = g->sp - 1;
527 b = g->sp;
529 if (SlotEq(a, b))
530 SetTrue(a);
531 else
532 SetFalse(a);
533 return errNone;
536 int objectNotIdentical(struct VMGlobals *g, int numArgsPushed)
538 PyrSlot *a, *b;
540 a = g->sp - 1;
541 b = g->sp;
543 if ( !SlotEq(a, b) )
544 SetTrue(a);
545 else
546 SetFalse(a);
547 return errNone;
551 int basicNewClear(struct VMGlobals *g, int numArgsPushed)
553 PyrSlot *a, *b;
554 int size;
555 PyrClass *classobj;
556 PyrObject *newobj;
558 a = g->sp - 1;
559 b = g->sp;
561 if (NotObj(a)) return errWrongType;
562 classobj = (PyrClass*)slotRawObject(a);
563 if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) {
564 // create an indexable object
565 if (NotInt(b)) {
566 if (IsFloat(b)) {
567 size = (int)slotRawFloat(b);
568 } else if (NotNil(b)) return errIndexNotAnInteger;
569 else size = 8;
570 } else {
571 size = slotRawInt(b);
573 if (size < 0) size = 0;
574 } else {
575 size = 0;
577 newobj = instantiateObject(g->gc, classobj, size, true, true);
578 SetObject(a, newobj);
579 return errNone;
582 int basicNewCopyArgsToInstanceVars(struct VMGlobals *g, int numArgsPushed);
583 int basicNewCopyArgsToInstanceVars(struct VMGlobals *g, int numArgsPushed)
585 PyrSlot *a, *b;
586 PyrClass *classobj;
587 PyrObject *newobj;
589 a = g->sp - numArgsPushed + 1;
590 b = a + 1;
592 if (NotObj(a)) return errWrongType;
593 classobj = (PyrClass*)slotRawObject(a);
594 if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) {
595 error("CopyArgs : object has no instance variables.\n");
596 return errFailed;
598 newobj = instantiateObject(g->gc, classobj, 0, true, true);
599 SetObject(a, newobj);
601 int length = sc_min(numArgsPushed-1, newobj->size);
602 for (int i=0; i<length; ++i) {
603 slotCopy(&newobj->slots[i],&b[i]);
606 return errNone;
611 int basicNew(struct VMGlobals *g, int numArgsPushed)
613 PyrSlot *a, *b;
614 int size;
615 PyrClass *classobj;
616 PyrObject *newobj;
618 a = g->sp - 1;
619 b = g->sp;
621 if (NotObj(a)) return errWrongType;
622 classobj = (PyrClass*)slotRawObject(a);
623 if (slotRawInt(&classobj->classFlags) & classHasIndexableInstances) {
624 // create an indexable object
625 if (NotInt(b)) {
626 if (IsFloat(b)) {
627 size = (int)slotRawFloat(b);
628 } else if (NotNil(b)) return errIndexNotAnInteger;
629 else size = 8;
630 } else {
631 size = slotRawInt(b);
633 if (size < 0) size = 0;
634 } else {
635 size = 0;
637 newobj = instantiateObject(g->gc, classobj, size, false, true);
638 SetObject(a, newobj);
639 return errNone;
643 bool isClosed(PyrBlock* fundef);
644 bool isClosed(PyrBlock* fundef)
646 return IsNil(&fundef->contextDef) && fundef->classptr == class_fundef;
649 bool isWithinClosed(PyrBlock* fundef);
650 bool isWithinClosed(PyrBlock* fundef)
652 while (fundef) {
653 if (isClosed(fundef)) return true;
654 fundef = slotRawBlock(&fundef->contextDef);
656 return false;
659 int prFunctionDefAsFunction(struct VMGlobals *g, int numArgsPushed);
660 int prFunctionDefAsFunction(struct VMGlobals *g, int numArgsPushed)
662 PyrSlot *a = g->sp;
664 if (!isClosed(slotRawBlock(a))) {
665 dumpObjectSlot(a);
666 error("Only closed FunctionDef may be converted to a Function using asFunction.\n");
667 return errFailed;
670 PyrClosure* closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, true);
672 closure->classptr = gSpecialClasses[op_class_func]->u.classobj;
673 closure->size = 2;
674 slotCopy(&closure->block,a);
675 slotCopy(&closure->context,&slotRawInterpreter(&g->process->interpreter)->context);
676 SetObject(a, closure);
677 return errNone;
680 int prFunctionDefDumpContexts(struct VMGlobals *g, int numArgsPushed);
681 int prFunctionDefDumpContexts(struct VMGlobals *g, int numArgsPushed)
683 PyrSlot *a = g->sp;
685 int i=0;
686 while (slotRawBlock(a)) {
687 post("%2d context %s %p\n", i++, slotRawSymbol(&slotRawObject(a)->classptr->name)->name, slotRawInt(&slotRawBlock(a)->contextDef));
688 a = &slotRawBlock(a)->contextDef;
690 return errNone;
695 int prFunctionDefIsClosed(struct VMGlobals *g, int numArgsPushed);
696 int prFunctionDefIsClosed(struct VMGlobals *g, int numArgsPushed)
698 PyrSlot *a = g->sp;
699 PyrBlock *block = slotRawBlock(a);
701 SetBool(a, isClosed(block));
702 return errNone;
705 int prFunctionDefIsWithinClosed(struct VMGlobals *g, int numArgsPushed);
706 int prFunctionDefIsWithinClosed(struct VMGlobals *g, int numArgsPushed)
708 PyrSlot *a = g->sp;
709 PyrBlock *block = slotRawBlock(a);
711 SetBool(a, isWithinClosed(block));
712 return errNone;
716 void reallocStack(struct VMGlobals *g, int stackNeeded, int stackDepth)
718 //PyrThread *thread = g->thread;
719 PyrGC *gc = g->gc;
720 int newStackSize = NEXTPOWEROFTWO(stackNeeded);
722 PyrObject* array = newPyrArray(gc, newStackSize, 0, false);
723 memcpy(array->slots, gc->Stack()->slots, stackDepth * sizeof(PyrSlot));
724 gc->SetStack(array);
725 gc->ToBlack(gc->Stack());
726 g->sp = array->slots + stackDepth - 1;
730 int blockValueArray(struct VMGlobals *g, int numArgsPushed)
732 PyrSlot *b;
733 PyrObject *array;
734 PyrList *list;
735 PyrSlot *pslot, *qslot;
736 int m, size;
738 //a = g->sp - numArgsPushed + 1;
739 b = g->sp;
741 if (IsObj(b)) {
742 if (slotRawObject(b)->classptr == class_array) {
743 array = (PyrObject*)slotRawObject(b);
744 above:
745 size = array->size;
747 PyrObject *stack = g->gc->Stack();
748 int stackDepth = g->sp - stack->slots + 1;
749 int stackSize = ARRAYMAXINDEXSIZE(stack);
750 int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations.
751 if (stackNeeded > stackSize) {
752 reallocStack(g, stackNeeded, stackDepth);
753 b = g->sp;
756 pslot = array->slots - 1;
757 qslot = b - 1;
758 //pend = (double*)(pslot + size);
759 //while (pslot<pend) slotCopy(++qslot, ++pslot);
760 for (m=0; m<size; ++m) slotCopy(++qslot, ++pslot);
762 g->sp += size - 1;
763 return blockValue(g, size+numArgsPushed-1);
765 } else if (slotRawObject(b)->classptr == class_list) {
766 list = slotRawList(b);
767 if (NotObj(&list->array)) return errWrongType;
768 array = slotRawObject(&list->array);
769 if (array->classptr != class_array) return errWrongType;
770 goto above;
771 } else { // last arg is not a list or array, so pass as normal
772 return blockValue(g, numArgsPushed);
774 } else {
775 return blockValue(g, numArgsPushed);
779 int blockValueEnvir(struct VMGlobals *g, int numArgsPushed);
781 int blockValueArrayEnvir(struct VMGlobals *g, int numArgsPushed);
782 int blockValueArrayEnvir(struct VMGlobals *g, int numArgsPushed)
784 PyrSlot *b;
785 PyrObject *array;
786 PyrList *list;
787 PyrSlot *pslot, *qslot;
788 int m, size;
790 //a = g->sp - numArgsPushed + 1;
791 b = g->sp;
793 if (IsObj(b)) {
794 if (slotRawObject(b)->classptr == class_array) {
795 array = (PyrObject*)slotRawObject(b);
796 above:
797 size = array->size;
799 PyrObject *stack = g->gc->Stack();
800 int stackDepth = g->sp - stack->slots + 1;
801 int stackSize = ARRAYMAXINDEXSIZE(stack);
802 int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations.
803 if (stackNeeded > stackSize) {
804 reallocStack(g, stackNeeded, stackDepth);
805 b = g->sp;
808 pslot = array->slots - 1;
809 qslot = b - 1;
810 //pend = (double*)(pslot + size);
811 //while (pslot<pend) slotCopy(++qslot, ++pslot);
812 for (m=0; m<size; ++m) slotCopy(++qslot, ++pslot);
814 g->sp += size - 1;
815 return blockValueEnvir(g, size+numArgsPushed-1);
817 } else if (slotRawObject(b)->classptr == class_list) {
818 list = slotRawList(b);
819 if (NotObj(&list->array)) return errWrongType;
820 array = slotRawObject(&list->array);
821 if (array->classptr != class_array) return errWrongType;
822 goto above;
823 } else { // last arg is not a list or array, so pass as normal
824 return blockValueEnvir(g, numArgsPushed);
826 } else {
827 return blockValueEnvir(g, numArgsPushed);
831 HOT int blockValue(struct VMGlobals *g, int numArgsPushed)
833 PyrSlot *args;
834 PyrSlot *vars;
835 PyrFrame *frame;
836 PyrSlot *pslot, *qslot;
837 PyrSlot *rslot;
838 PyrObject *proto;
839 int i, m, mmax, numtemps;
840 PyrBlock *block;
841 PyrFrame *context;
842 PyrFrame *caller;
843 PyrFrame *homeContext;
844 PyrClosure *closure;
845 PyrMethodRaw *methraw;
847 #if TAILCALLOPTIMIZE
848 int tailCall = g->tailCall;
849 if (tailCall) {
850 if (tailCall == 1) {
851 returnFromMethod(g);
852 } else {
853 returnFromBlock(g);
856 #endif
858 g->execMethod = 30;
860 args = g->sp - numArgsPushed + 1;
862 numArgsPushed -- ;
863 g->numpop = 0;
865 closure = (PyrClosure*)slotRawObject(args);
866 block = slotRawBlock(&closure->block);
867 context = slotRawFrame(&closure->context);
869 proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL;
870 methraw = METHRAW(block);
871 numtemps = methraw->numtemps;
872 caller = g->frame;
874 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
875 vars = frame->vars - 1;
876 frame->classptr = class_frame;
877 frame->size = FRAMESIZE + numtemps;
878 SetObject(&frame->method, block);
879 slotCopy(&frame->homeContext,&context->homeContext);
880 slotCopy(&frame->context,&closure->context);
882 if (caller) {
883 SetPtr(&caller->ip, g->ip);
884 SetObject(&frame->caller, g->frame);
885 } else {
886 SetInt(&frame->caller, 0);
888 SetPtr(&frame->ip, 0);
891 g->sp = args - 1;
892 g->ip = slotRawInt8Array(&block->code)->b - 1;
893 g->frame = frame;
894 g->block = block;
896 if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
897 /* push all args to frame */
898 qslot = args;
899 pslot = vars;
901 for (m=0; m<numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
903 /* push default arg values */
904 pslot = vars + numArgsPushed;
905 qslot = proto->slots + numArgsPushed - 1;
906 for (m=0; m<numtemps - numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
907 } else if (methraw->varargs) {
908 PyrObject *list;
909 PyrSlot *lslot;
911 /* push all normal args to frame */
912 qslot = args;
913 pslot = vars;
914 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
916 /* push list */
917 i = numArgsPushed - methraw->numargs;
918 list = newPyrArray(g->gc, i, 0, false);
919 list->size = i;
921 rslot = pslot+1;
922 SetObject(rslot, list);
923 //SetObject(vars + methraw->numargs + 1, list);
925 /* put extra args into list */
926 lslot = list->slots - 1;
927 // fixed and raw sizes are zero
928 for (m=0; m<i; ++m) slotCopy(++lslot, ++qslot);
930 if (methraw->numvars) {
931 /* push default keyword and var values */
932 pslot = vars + methraw->numargs + 1;
933 qslot = proto->slots + methraw->numargs;
934 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
936 } else {
937 if (methraw->numargs) {
938 /* push all args to frame */
939 qslot = args;
940 pslot = vars;
941 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
943 if (methraw->numvars) {
944 /* push default keyword and var values */
945 pslot = vars + methraw->numargs;
946 qslot = proto->slots + methraw->numargs - 1;
947 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
951 homeContext = slotRawFrame(&frame->homeContext);
952 if (homeContext) {
953 PyrMethodRaw *methraw;
954 g->method = slotRawMethod(&homeContext->method);
955 methraw = METHRAW(g->method);
956 slotCopy(&g->receiver,&homeContext->vars[0]);
957 } else {
958 slotCopy(&g->receiver,&g->process->interpreter);
961 return errNone;
964 int blockValueWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed);
965 int blockValueWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed)
967 PyrSlot *args;
968 PyrSlot *vars;
969 PyrFrame *frame;
970 PyrSlot *pslot, *qslot;
971 PyrSlot *rslot;
972 PyrObject *proto;
973 int i, j, m, mmax, numtemps, numArgsPushed;
974 PyrBlock *block;
975 PyrFrame *context;
976 PyrFrame *caller;
977 PyrFrame *homeContext;
978 PyrClosure *closure;
979 PyrMethodRaw *methraw;
981 #if TAILCALLOPTIMIZE
982 int tailCall = g->tailCall;
983 if (tailCall) {
984 if (tailCall == 1) {
985 returnFromMethod(g);
986 } else {
987 returnFromBlock(g);
990 #endif
992 g->execMethod = 40;
994 args = g->sp - allArgsPushed + 1;
996 allArgsPushed -- ;
997 g->numpop = 0;
999 closure = (PyrClosure*)slotRawObject(args);
1000 block = slotRawBlock(&closure->block);
1001 context = slotRawFrame(&closure->context);
1003 proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL;
1005 methraw = METHRAW(block);
1006 numtemps = methraw->numtemps;
1007 caller = g->frame;
1008 numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1);
1010 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
1011 vars = frame->vars - 1;
1012 frame->classptr = class_frame;
1013 frame->size = FRAMESIZE + numtemps;
1014 SetObject(&frame->method, block);
1015 slotCopy(&frame->homeContext,&context->homeContext);
1016 slotCopy(&frame->context,&closure->context);
1018 if (caller) {
1019 SetPtr(&caller->ip, g->ip);
1020 SetObject(&frame->caller, g->frame);
1021 } else {
1022 SetInt(&frame->caller, 0);
1024 SetPtr(&frame->ip, 0);
1026 g->sp = args - 1;
1027 g->ip = slotRawInt8Array(&block->code)->b - 1;
1028 g->frame = frame;
1029 g->block = block;
1031 if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
1032 /* push all args to frame */
1033 qslot = args;
1034 pslot = vars;
1036 for (m=0; m<numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1038 /* push default arg values */
1039 pslot = vars + numArgsPushed;
1040 qslot = proto->slots + numArgsPushed - 1;
1041 for (m=0; m<numtemps - numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1042 } else if (methraw->varargs) {
1043 PyrObject *list;
1044 PyrSlot *lslot;
1046 /* push all normal args to frame */
1047 qslot = args;
1048 pslot = vars;
1049 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1051 /* push list */
1052 i = numArgsPushed - methraw->numargs;
1053 list = newPyrArray(g->gc, i, 0, false);
1054 list->size = i;
1056 rslot = pslot+1;
1057 SetObject(rslot, list);
1058 //SetObject(vars + methraw->numargs + 1, list);
1060 /* put extra args into list */
1061 lslot = list->slots - 1;
1062 // fixed and raw sizes are zero
1063 //lend = lslot + i;
1064 //while (lslot < lend) slotCopy(++lslot, ++qslot);
1065 for (m=0; m<i; ++m) slotCopy(++lslot, ++qslot);
1067 if (methraw->numvars) {
1068 /* push default keyword and var values */
1069 pslot = vars + methraw->numargs + 1;
1070 qslot = proto->slots + methraw->numargs;
1071 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1073 } else {
1074 if (methraw->numargs) {
1075 /* push all args to frame */
1076 qslot = args;
1077 pslot = vars;
1078 //pend = pslot + methraw->numargs;
1079 //while (pslot < pend) slotCopy(++pslot, ++qslot);
1080 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1082 if (methraw->numvars) {
1083 /* push default keyword and var values */
1084 pslot = vars + methraw->numargs;
1085 qslot = proto->slots + methraw->numargs - 1;
1086 //pend = pslot + methraw->numvars;
1087 //while (pslot<pend) slotCopy(++pslot, ++qslot);
1088 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1091 // do keyword lookup:
1092 if (numKeyArgsPushed && methraw->posargs) {
1093 PyrSlot *key;
1094 PyrSymbol **name0, **name;
1095 name0 = slotRawSymbolArray(&block->argNames)->symbols;
1096 key = args + numArgsPushed + 1;
1097 for (i=0; i<numKeyArgsPushed; ++i, key+=2) {
1098 name = name0;
1099 for (j=0; j<methraw->posargs; ++j, ++name) {
1100 if (*name == slotRawSymbol(key)) {
1101 slotCopy(&vars[j+1],&key[1]);
1102 goto found1;
1105 if (gKeywordError) {
1106 post("WARNING: keyword arg '%s' not found in call to function.\n",
1107 slotRawSymbol(key)->name);
1109 found1: ;
1113 homeContext = slotRawFrame(&frame->homeContext);
1114 if (homeContext) {
1115 PyrMethodRaw *methraw;
1116 g->method = slotRawMethod(&homeContext->method);
1117 methraw = METHRAW(g->method);
1118 slotCopy(&g->receiver,&homeContext->vars[0]);
1119 } else {
1120 slotCopy(&g->receiver,&g->process->interpreter);
1122 return errNone;
1125 bool identDict_lookupNonNil(PyrObject *dict, PyrSlot *key, int hash, PyrSlot *result);
1127 int blockValueEnvir(struct VMGlobals *g, int numArgsPushed)
1129 PyrSlot *args;
1130 PyrSlot *vars;
1131 PyrFrame *frame;
1132 PyrSlot *pslot, *qslot;
1133 PyrSlot *rslot;
1134 PyrObject *proto;
1135 int i, m, mmax, numtemps;
1136 PyrBlock *block;
1137 PyrFrame *context;
1138 PyrFrame *caller;
1139 PyrFrame *homeContext;
1140 PyrClosure *closure;
1141 PyrMethodRaw *methraw;
1142 PyrSlot *curEnvirSlot;
1144 #if TAILCALLOPTIMIZE
1145 int tailCall = g->tailCall;
1146 if (tailCall) {
1147 if (tailCall == 1) {
1148 returnFromMethod(g);
1149 } else {
1150 returnFromBlock(g);
1153 #endif
1155 g->execMethod = 50;
1157 args = g->sp - numArgsPushed + 1;
1159 numArgsPushed -- ;
1160 g->numpop = 0;
1162 closure = (PyrClosure*)slotRawObject(args);
1163 block = slotRawBlock(&closure->block);
1164 context = slotRawFrame(&closure->context);
1166 proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL;
1168 methraw = METHRAW(block);
1169 numtemps = methraw->numtemps;
1170 caller = g->frame;
1172 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
1173 vars = frame->vars - 1;
1174 frame->classptr = class_frame;
1175 frame->size = FRAMESIZE + numtemps;
1176 SetObject(&frame->method, block);
1177 slotCopy(&frame->homeContext,&context->homeContext);
1178 slotCopy(&frame->context,&closure->context);
1180 if (caller) {
1181 SetPtr(&caller->ip, g->ip);
1182 SetObject(&frame->caller, g->frame);
1183 } else {
1184 SetInt(&frame->caller, 0);
1186 SetPtr(&frame->ip, 0);
1189 g->sp = args - 1;
1190 g->ip = slotRawInt8Array(&block->code)->b - 1;
1191 g->frame = frame;
1192 g->block = block;
1194 if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
1195 /* push all args to frame */
1196 qslot = args;
1197 pslot = vars;
1199 for (m=0; m<numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1201 /* push default arg values */
1202 pslot = vars + numArgsPushed;
1203 qslot = proto->slots + numArgsPushed - 1;
1204 for (m=0; m<numtemps - numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1206 // replace defaults with environment variables
1207 curEnvirSlot = &g->classvars->slots[1]; // currentEnvironment is the second class var.
1209 if (isKindOfSlot(curEnvirSlot, s_identitydictionary->u.classobj)) {
1210 PyrSymbol **argNames;
1211 argNames = slotRawSymbolArray(&block->argNames)->symbols;
1212 for (m=numArgsPushed; m<methraw->numargs; ++m) {
1213 // replace the args with values from the environment if they exist
1214 PyrSlot keyslot;
1215 SetSymbol(&keyslot, argNames[m]);
1216 identDict_lookupNonNil(slotRawObject(curEnvirSlot), &keyslot, calcHash(&keyslot), vars+m+1);
1219 } else if (methraw->varargs) {
1220 PyrObject *list;
1221 PyrSlot *lslot;
1223 /* push all normal args to frame */
1224 qslot = args;
1225 pslot = vars;
1226 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1228 /* push list */
1229 i = numArgsPushed - methraw->numargs;
1230 list = newPyrArray(g->gc, i, 0, false);
1231 list->size = i;
1233 rslot = pslot+1;
1234 SetObject(rslot, list);
1235 //SetObject(vars + methraw->numargs + 1, list);
1237 /* put extra args into list */
1238 lslot = list->slots - 1;
1239 // fixed and raw sizes are zero
1240 for (m=0; m<i; ++m) slotCopy(++lslot, ++qslot);
1242 if (methraw->numvars) {
1243 /* push default keyword and var values */
1244 pslot = vars + methraw->numargs + 1;
1245 qslot = proto->slots + methraw->numargs;
1246 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1248 } else {
1249 if (methraw->numargs) {
1250 /* push all args to frame */
1251 qslot = args;
1252 pslot = vars;
1253 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1255 if (methraw->numvars) {
1256 /* push default keyword and var values */
1257 pslot = vars + methraw->numargs;
1258 qslot = proto->slots + methraw->numargs - 1;
1259 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1263 homeContext = slotRawFrame(&frame->homeContext);
1264 if (homeContext) {
1265 PyrMethodRaw *methraw;
1266 g->method = slotRawMethod(&homeContext->method);
1267 methraw = METHRAW(g->method);
1268 slotCopy(&g->receiver,&homeContext->vars[0]);
1269 } else {
1270 slotCopy(&g->receiver,&g->process->interpreter);
1272 return errNone;
1275 int blockValueEnvirWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed);
1276 int blockValueEnvirWithKeys(VMGlobals *g, int allArgsPushed, int numKeyArgsPushed)
1278 PyrSlot *args;
1279 PyrSlot *vars;
1280 PyrFrame *frame;
1281 PyrSlot *pslot, *qslot;
1282 PyrSlot *rslot;
1283 PyrObject *proto;
1284 int i, j, m, mmax, numtemps, numArgsPushed;
1285 PyrBlock *block;
1286 PyrFrame *context;
1287 PyrFrame *caller;
1288 PyrFrame *homeContext;
1289 PyrClosure *closure;
1290 PyrMethodRaw *methraw;
1291 PyrSlot *curEnvirSlot;
1293 #if TAILCALLOPTIMIZE
1294 int tailCall = g->tailCall;
1295 if (tailCall) {
1296 if (tailCall == 1) {
1297 returnFromMethod(g);
1298 } else {
1299 returnFromBlock(g);
1302 #endif
1304 g->execMethod = 60;
1306 args = g->sp - allArgsPushed + 1;
1308 allArgsPushed -- ;
1309 g->numpop = 0;
1311 closure = (PyrClosure*)slotRawObject(args);
1312 block = slotRawBlock(&closure->block);
1313 context = slotRawFrame(&closure->context);
1315 proto = IsObj(&block->prototypeFrame) ? slotRawObject(&block->prototypeFrame) : NULL;
1317 methraw = METHRAW(block);
1318 numtemps = methraw->numtemps;
1319 caller = g->frame;
1320 numArgsPushed = allArgsPushed - (numKeyArgsPushed<<1);
1322 frame = (PyrFrame*)g->gc->NewFrame(methraw->frameSize, 0, obj_slot, methraw->needsHeapContext);
1323 vars = frame->vars - 1;
1324 frame->classptr = class_frame;
1325 frame->size = FRAMESIZE + numtemps;
1326 SetObject(&frame->method, block);
1327 slotCopy(&frame->homeContext,&context->homeContext);
1328 slotCopy(&frame->context,&closure->context);
1330 if (caller) {
1331 SetPtr(&caller->ip, g->ip);
1332 SetObject(&frame->caller, g->frame);
1333 } else {
1334 SetInt(&frame->caller, 0);
1336 SetPtr(&frame->ip, 0);
1339 g->sp = args - 1;
1340 g->ip = slotRawInt8Array(&block->code)->b - 1;
1341 g->frame = frame;
1342 g->block = block;
1344 if (numArgsPushed <= methraw->numargs) { /* not enough args pushed */
1345 /* push all args to frame */
1346 qslot = args;
1347 pslot = vars;
1349 for (m=0; m<numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1351 /* push default arg values */
1352 pslot = vars + numArgsPushed;
1353 qslot = proto->slots + numArgsPushed - 1;
1354 for (m=0; m<numtemps - numArgsPushed; ++m) slotCopy(++pslot, ++qslot);
1356 // replace defaults with environment variables
1357 curEnvirSlot = &g->classvars->slots[1]; // currentEnvironment is the second class var.
1359 if (isKindOfSlot(curEnvirSlot, s_identitydictionary->u.classobj)) {
1360 PyrSymbol **argNames;
1361 argNames = slotRawSymbolArray(&block->argNames)->symbols;
1362 for (m=numArgsPushed; m<methraw->numargs; ++m) {
1363 // replace the args with values from the environment if they exist
1364 PyrSlot keyslot;
1365 SetSymbol(&keyslot, argNames[m]);
1366 identDict_lookupNonNil(slotRawObject(curEnvirSlot), &keyslot, calcHash(&keyslot), vars+m+1);
1371 } else if (methraw->varargs) {
1372 PyrObject *list;
1373 PyrSlot *lslot;
1375 /* push all normal args to frame */
1376 qslot = args;
1377 pslot = vars;
1378 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1380 /* push list */
1381 i = numArgsPushed - methraw->numargs;
1382 list = newPyrArray(g->gc, i, 0, false);
1383 list->size = i;
1385 rslot = pslot+1;
1386 SetObject(rslot, list);
1387 //SetObject(vars + methraw->numargs + 1, list);
1389 /* put extra args into list */
1390 lslot = list->slots - 1;
1391 // fixed and raw sizes are zero
1392 //lend = lslot + i;
1393 //while (lslot < lend) slotCopy(++lslot, ++qslot);
1394 for (m=0; m<i; ++m) slotCopy(++lslot, ++qslot);
1396 if (methraw->numvars) {
1397 /* push default keyword and var values */
1398 pslot = vars + methraw->numargs + 1;
1399 qslot = proto->slots + methraw->numargs;
1400 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1402 } else {
1403 if (methraw->numargs) {
1404 /* push all args to frame */
1405 qslot = args;
1406 pslot = vars;
1407 //pend = pslot + methraw->numargs;
1408 //while (pslot < pend) slotCopy(++pslot, ++qslot);
1409 for (m=0,mmax=methraw->numargs; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1411 if (methraw->numvars) {
1412 /* push default keyword and var values */
1413 pslot = vars + methraw->numargs;
1414 qslot = proto->slots + methraw->numargs - 1;
1415 //pend = pslot + methraw->numvars;
1416 //while (pslot<pend) slotCopy(++pslot, ++qslot);
1417 for (m=0,mmax=methraw->numvars; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1420 // do keyword lookup:
1421 if (numKeyArgsPushed && methraw->posargs) {
1422 PyrSymbol **name0, **name;
1423 PyrSlot *key;
1424 name0 = slotRawSymbolArray(&block->argNames)->symbols;
1425 key = args + numArgsPushed + 1;
1426 for (i=0; i<numKeyArgsPushed; ++i, key+=2) {
1427 name = name0;
1428 for (j=0; j<methraw->posargs; ++j, ++name) {
1429 if (*name == slotRawSymbol(key)) {
1430 slotCopy(&vars[j+1],&key[1]);
1431 goto found1;
1434 if (gKeywordError) {
1435 post("WARNING: keyword arg '%s' not found in call to function.\n",
1436 slotRawSymbol(key)->name);
1438 found1: ;
1442 homeContext = slotRawFrame(&frame->homeContext);
1443 if (homeContext) {
1444 PyrMethodRaw *methraw;
1445 g->method = slotRawMethod(&homeContext->method);
1446 methraw = METHRAW(g->method);
1447 slotCopy(&g->receiver,&homeContext->vars[0]);
1448 } else {
1449 slotCopy(&g->receiver,&g->process->interpreter);
1451 return errNone;
1455 int objectPerform(struct VMGlobals *g, int numArgsPushed)
1457 PyrSlot *recvrSlot, *selSlot, *listSlot;
1458 PyrSlot *pslot, *qslot;
1459 PyrSymbol *selector;
1460 int m, mmax;
1462 recvrSlot = g->sp - numArgsPushed + 1;
1463 selSlot = recvrSlot + 1;
1464 if (IsSym(selSlot)) {
1465 selector = slotRawSymbol(selSlot);
1466 // move args down one to fill selector's position
1467 pslot = selSlot - 1;
1468 qslot = selSlot;
1469 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(++pslot, ++qslot);
1470 g->sp -- ;
1471 numArgsPushed -- ;
1472 // now the stack looks just like it would for a normal message send
1473 } else if (IsObj(selSlot)) {
1474 listSlot = selSlot;
1475 if (slotRawObject(listSlot)->classptr == class_list) {
1476 listSlot = slotRawObject(listSlot)->slots;
1478 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1479 goto badselector;
1481 PyrObject *array = slotRawObject(listSlot);
1482 if (array->size < 1) {
1483 error("Array must have a selector.\n");
1484 return errFailed;
1486 selSlot = array->slots;
1487 selector = slotRawSymbol(selSlot);
1489 if (numArgsPushed>2) {
1490 qslot = recvrSlot + numArgsPushed;
1491 pslot = recvrSlot + numArgsPushed + array->size - 2;
1492 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(--pslot, --qslot);
1495 pslot = recvrSlot;
1496 qslot = selSlot;
1497 for (m=0,mmax=array->size-1; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1499 g->sp += array->size - 2;
1500 numArgsPushed += array->size - 2;
1501 // now the stack looks just like it would for a normal message send
1503 } else {
1504 badselector:
1505 error("perform selector not a Symbol or Array.\n");
1506 dumpObjectSlot(selSlot);
1507 return errWrongType;
1510 sendMessage(g, selector, numArgsPushed);
1511 g->numpop = 0;
1512 return errNone;
1515 int objectPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed);
1516 int objectPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed)
1518 PyrSlot *recvrSlot, *selSlot, *listSlot;
1519 PyrSlot *pslot, *qslot;
1520 PyrSymbol *selector;
1521 int m, mmax;
1523 recvrSlot = g->sp - numArgsPushed + 1;
1524 selSlot = recvrSlot + 1;
1525 if (IsSym(selSlot)) {
1526 selector = slotRawSymbol(selSlot);
1527 // move args down one to fill selector's position
1528 pslot = selSlot - 1;
1529 qslot = selSlot;
1530 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(++pslot, ++qslot);
1531 g->sp -- ;
1532 numArgsPushed -- ;
1533 // now the stack looks just like it would for a normal message send
1534 } else if (IsObj(selSlot)) {
1535 listSlot = selSlot;
1536 if (slotRawObject(listSlot)->classptr == class_list) {
1537 listSlot = slotRawObject(listSlot)->slots;
1539 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1540 goto badselector;
1542 PyrObject *array = slotRawObject(listSlot);
1543 if (array->size < 1) {
1544 error("Array must have a selector.\n");
1545 return errFailed;
1547 selSlot = array->slots;
1548 selector = slotRawSymbol(selSlot);
1550 if (numArgsPushed>2) {
1551 qslot = recvrSlot + numArgsPushed;
1552 pslot = recvrSlot + numArgsPushed + array->size - 2;
1553 for (m=0; m<numArgsPushed - 2; ++m) *--pslot = *--qslot;
1556 pslot = recvrSlot;
1557 qslot = selSlot;
1558 for (m=0,mmax=array->size-1; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1560 g->sp += array->size - 2;
1561 numArgsPushed += array->size - 2;
1562 // now the stack looks just like it would for a normal message send
1564 } else {
1565 badselector:
1566 error("perform selector not a Symbol or Array.\n");
1567 dumpObjectSlot(selSlot);
1568 return errWrongType;
1571 sendMessageWithKeys(g, selector, numArgsPushed, numKeyArgsPushed);
1572 g->numpop = 0;
1573 return errNone;
1577 int objectPerformList(struct VMGlobals *g, int numArgsPushed)
1579 PyrSlot *recvrSlot, *selSlot, *listSlot;
1580 PyrSlot *pslot, *qslot;
1581 PyrSymbol *selector;
1582 int m, mmax, numargslots;
1583 PyrObject *array;
1586 recvrSlot = g->sp - numArgsPushed + 1;
1587 selSlot = recvrSlot + 1;
1588 listSlot = g->sp;
1589 numargslots = numArgsPushed - 3;
1590 if (NotSym(selSlot)) {
1591 error("Selector not a Symbol :\n");
1592 return errWrongType;
1594 selector = slotRawSymbol(selSlot);
1596 if (NotObj(listSlot)) {
1597 return objectPerform(g, numArgsPushed);
1599 if (slotRawObject(listSlot)->classptr == class_array) {
1600 doarray:
1601 array = slotRawObject(listSlot);
1603 PyrObject *stack = g->gc->Stack();
1604 int stackDepth = g->sp - stack->slots + 1;
1605 int stackSize = ARRAYMAXINDEXSIZE(stack);
1606 int stackNeeded = stackDepth + array->size + 64; // 64 to allow extra for normal stack operations.
1607 if (stackNeeded > stackSize) {
1608 reallocStack(g, stackNeeded, stackDepth);
1609 recvrSlot = g->sp - numArgsPushed + 1;
1610 selSlot = recvrSlot + 1;
1613 pslot = recvrSlot;
1614 if (numargslots>0) {
1615 qslot = selSlot;
1616 for (m=0; m<numargslots; ++m) slotCopy(++pslot, ++qslot);
1617 } else numargslots = 0;
1618 qslot = array->slots - 1;
1619 for (m=0,mmax=array->size; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1620 } else if (slotRawObject(listSlot)->classptr == class_list) {
1621 listSlot = slotRawObject(listSlot)->slots;
1622 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1623 error("List array not an Array.\n");
1624 dumpObjectSlot(listSlot);
1625 return errWrongType;
1627 goto doarray;
1628 } else {
1629 return objectPerform(g, numArgsPushed);
1631 g->sp += array->size - 2;
1632 numArgsPushed = numargslots + array->size + 1;
1633 // now the stack looks just like it would for a normal message send
1635 sendMessage(g, selector, numArgsPushed);
1636 g->numpop = 0;
1638 return errNone;
1642 int objectSuperPerform(struct VMGlobals *g, int numArgsPushed)
1644 PyrSlot *recvrSlot, *selSlot, *listSlot;
1645 PyrSlot *pslot, *qslot;
1646 PyrSymbol *selector;
1647 int m, mmax;
1649 recvrSlot = g->sp - numArgsPushed + 1;
1651 PyrClass* classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj;
1652 if (!isKindOfSlot(recvrSlot, classobj)) {
1653 error("superPerform must be called with 'this' as the receiver.\n");
1654 return errFailed;
1657 selSlot = recvrSlot + 1;
1658 if (IsSym(selSlot)) {
1659 selector = slotRawSymbol(selSlot);
1660 // move args down one to fill selector's position
1661 pslot = selSlot - 1;
1662 qslot = selSlot;
1663 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(++pslot, ++qslot);
1664 g->sp -- ;
1665 numArgsPushed -- ;
1666 // now the stack looks just like it would for a normal message send
1667 } else if (IsObj(selSlot)) {
1668 listSlot = selSlot;
1669 if (slotRawObject(listSlot)->classptr == class_list) {
1670 listSlot = slotRawObject(listSlot)->slots;
1672 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1673 goto badselector;
1675 PyrObject *array = slotRawObject(listSlot);
1676 if (array->size < 1) {
1677 error("Array must have a selector.\n");
1678 return errFailed;
1680 selSlot = array->slots;
1681 selector = slotRawSymbol(selSlot);
1683 if (numArgsPushed>2) {
1684 qslot = recvrSlot + numArgsPushed;
1685 pslot = recvrSlot + numArgsPushed + array->size - 2;
1686 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(--pslot, --qslot);
1689 pslot = recvrSlot;
1690 qslot = selSlot;
1691 for (m=0,mmax=array->size-1; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1693 g->sp += array->size - 2;
1694 numArgsPushed += array->size - 2;
1695 // now the stack looks just like it would for a normal message send
1697 } else {
1698 badselector:
1699 error("perform selector not a Symbol or Array.\n");
1700 dumpObjectSlot(selSlot);
1701 return errWrongType;
1704 sendSuperMessage(g, selector, numArgsPushed);
1705 g->numpop = 0;
1706 return errNone;
1709 int objectSuperPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed);
1710 int objectSuperPerformWithKeys(VMGlobals *g, int numArgsPushed, int numKeyArgsPushed)
1712 PyrSlot *recvrSlot, *selSlot, *listSlot;
1713 PyrSlot *pslot, *qslot;
1714 PyrSymbol *selector;
1715 int m, mmax;
1717 recvrSlot = g->sp - numArgsPushed + 1;
1719 PyrClass* classobj = slotRawSymbol(&slotRawClass(&g->method->ownerclass)->superclass)->u.classobj;
1720 if (!isKindOfSlot(recvrSlot, classobj)) {
1721 error("superPerform must be called with 'this' as the receiver.\n");
1722 return errFailed;
1725 selSlot = recvrSlot + 1;
1726 if (IsSym(selSlot)) {
1727 selector = slotRawSymbol(selSlot);
1728 // move args down one to fill selector's position
1729 pslot = selSlot - 1;
1730 qslot = selSlot;
1731 for (m=0; m<numArgsPushed - 2; ++m) slotCopy(++pslot, ++qslot);
1732 g->sp -- ;
1733 numArgsPushed -- ;
1734 // now the stack looks just like it would for a normal message send
1735 } else if (IsObj(selSlot)) {
1736 listSlot = selSlot;
1737 if (slotRawObject(listSlot)->classptr == class_list) {
1738 listSlot = slotRawObject(listSlot)->slots;
1740 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1741 goto badselector;
1743 PyrObject *array = slotRawObject(listSlot);
1744 if (array->size < 1) {
1745 error("Array must have a selector.\n");
1746 return errFailed;
1748 selSlot = array->slots;
1749 selector = slotRawSymbol(selSlot);
1751 if (numArgsPushed>2) {
1752 qslot = recvrSlot + numArgsPushed;
1753 pslot = recvrSlot + numArgsPushed + array->size - 2;
1754 for (m=0; m<numArgsPushed - 2; ++m) *--pslot = *--qslot;
1757 pslot = recvrSlot;
1758 qslot = selSlot;
1759 for (m=0,mmax=array->size-1; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1761 g->sp += array->size - 2;
1762 numArgsPushed += array->size - 2;
1763 // now the stack looks just like it would for a normal message send
1765 } else {
1766 badselector:
1767 error("perform selector not a Symbol or Array.\n");
1768 dumpObjectSlot(selSlot);
1769 return errWrongType;
1772 sendSuperMessageWithKeys(g, selector, numArgsPushed, numKeyArgsPushed);
1773 g->numpop = 0;
1774 return errNone;
1778 int objectSuperPerformList(struct VMGlobals *g, int numArgsPushed)
1780 PyrSlot *recvrSlot, *selSlot, *listSlot;
1781 PyrSlot *pslot, *qslot;
1782 PyrSymbol *selector;
1783 int m, mmax, numargslots;
1784 PyrObject *array;
1786 recvrSlot = g->sp - numArgsPushed + 1;
1787 selSlot = recvrSlot + 1;
1788 listSlot = g->sp;
1789 numargslots = numArgsPushed - 3;
1790 if (NotSym(selSlot)) {
1791 error("Selector not a Symbol :\n");
1792 return errWrongType;
1794 selector = slotRawSymbol(selSlot);
1795 if (NotObj(listSlot)) {
1796 return objectPerform(g, numArgsPushed);
1798 if (slotRawObject(listSlot)->classptr == class_array) {
1799 doarray:
1800 pslot = recvrSlot;
1801 if (numargslots>0) {
1802 qslot = selSlot;
1803 for (m=0; m<numargslots; ++m) slotCopy(++pslot, ++qslot);
1804 } else numargslots = 0;
1805 array = slotRawObject(listSlot);
1806 qslot = array->slots - 1;
1807 for (m=0,mmax=array->size; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1808 } else if (slotRawObject(listSlot)->classptr == class_list) {
1809 listSlot = slotRawObject(listSlot)->slots;
1810 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1811 error("List array not an Array.\n");
1812 dumpObjectSlot(listSlot);
1813 return errWrongType;
1815 goto doarray;
1816 } else {
1817 return objectSuperPerform(g, numArgsPushed);
1819 g->sp += array->size - 2;
1820 numArgsPushed = numargslots + array->size + 1;
1821 // now the stack looks just like it would for a normal message send
1823 sendSuperMessage(g, selector, numArgsPushed);
1824 g->numpop = 0;
1825 return errNone;
1831 int objectPerformSelList(struct VMGlobals *g, int numArgsPushed)
1833 PyrSlot *recvrSlot, *selSlot, *listSlot;
1834 PyrSlot *pslot, *qslot;
1835 PyrSymbol *selector;
1836 int m, mmax;
1837 PyrObject *array;
1839 recvrSlot = g->sp - 1;
1840 listSlot = g->sp;
1842 if (NotObj(listSlot)) {
1843 error("Expected Array or List.. Got :\n");
1844 dumpObjectSlot(listSlot);
1845 return errWrongType;
1847 if (slotRawObject(listSlot)->classptr == class_array) {
1848 doarray:
1849 array = slotRawObject(listSlot);
1851 selSlot = array->slots;
1852 if (NotSym(selSlot)) {
1853 error("Selector not a Symbol :\n");
1854 return errWrongType;
1856 selector = slotRawSymbol(selSlot);
1858 pslot = recvrSlot;
1859 qslot = selSlot;
1860 for (m=0,mmax=array->size-1; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1861 } else if (slotRawObject(listSlot)->classptr == class_list) {
1862 listSlot = slotRawObject(listSlot)->slots;
1863 if (NotObj(listSlot) || slotRawObject(listSlot)->classptr != class_array) {
1864 error("List array not an Array.\n");
1865 dumpObjectSlot(listSlot);
1866 return errWrongType;
1868 goto doarray;
1869 } else {
1870 error("Expected Array or List.. Got :\n");
1871 dumpObjectSlot(listSlot);
1872 return errWrongType;
1874 g->sp += array->size - 2;
1875 numArgsPushed = array->size;
1876 // now the stack looks just like it would for a normal message send
1878 sendMessage(g, selector, numArgsPushed);
1879 g->numpop = 0;
1880 return errNone;
1884 int arrayPerformMsg(struct VMGlobals *g, int numArgsPushed);
1885 int arrayPerformMsg(struct VMGlobals *g, int numArgsPushed)
1887 PyrSlot *recvrSlot, *selSlot, *arraySlot;
1888 PyrSlot *pslot, *qslot;
1889 PyrSymbol *selector;
1890 int m, mmax, numargslots;
1891 PyrObject *array;
1893 arraySlot = g->sp - numArgsPushed + 1;
1894 array = slotRawObject(arraySlot);
1895 if (array->size < 2) {
1896 error("Array must contain a receiver and a selector.\n");
1897 return errFailed;
1899 recvrSlot = array->slots;
1900 selSlot = recvrSlot + 1;
1901 numargslots = numArgsPushed - 1;
1902 if (NotSym(selSlot)) {
1903 error("Selector not a Symbol :\n");
1904 return errWrongType;
1907 selector = slotRawSymbol(selSlot);
1909 slotCopy(arraySlot,recvrSlot);
1911 if (numargslots>0) {
1912 qslot = arraySlot + numargslots + 1;
1913 pslot = arraySlot + numargslots + array->size - 1;
1914 for (m=0; m<numargslots; ++m) slotCopy(--pslot, --qslot);
1915 } else numargslots = 0;
1917 pslot = arraySlot;
1918 qslot = selSlot;
1919 for (m=0,mmax=array->size-2; m<mmax; ++m) slotCopy(++pslot, ++qslot);
1921 g->sp += array->size - 2;
1922 numArgsPushed = numargslots + array->size - 1;
1924 // now the stack looks just like it would for a normal message send
1926 sendMessage(g, selector, numArgsPushed);
1927 g->numpop = 0;
1928 return errNone;
1931 int objectDump(struct VMGlobals *g, int numArgsPushed)
1933 PyrSlot *a;
1935 a = g->sp;
1936 dumpObjectSlot(a);
1937 return errNone;
1941 int prTotalFree(struct VMGlobals *g, int numArgsPushed);
1942 int prTotalFree(struct VMGlobals *g, int numArgsPushed)
1944 PyrSlot *a = g->sp;
1945 SetInt(a, g->allocPool->TotalFree());
1946 return errNone;
1949 int prLargestFreeBlock(struct VMGlobals *g, int numArgsPushed);
1950 int prLargestFreeBlock(struct VMGlobals *g, int numArgsPushed)
1952 PyrSlot *a = g->sp;
1953 SetInt(a, g->allocPool->LargestFreeChunk());
1954 return errNone;
1957 int dumpGCinfo(struct VMGlobals *g, int numArgsPushed);
1958 int dumpGCinfo(struct VMGlobals *g, int numArgsPushed)
1960 g->gc->DumpInfo();
1961 return errNone;
1964 int dumpGCdumpGrey(struct VMGlobals *g, int numArgsPushed);
1965 int dumpGCdumpGrey(struct VMGlobals *g, int numArgsPushed)
1967 g->gc->DumpGrey();
1968 return errNone;
1971 int dumpGCdumpSet(struct VMGlobals *g, int numArgsPushed);
1972 int dumpGCdumpSet(struct VMGlobals *g, int numArgsPushed)
1974 PyrSlot *b = g->sp;
1975 int set;
1976 int err = slotIntVal(b, &set);
1977 if (err) return err;
1979 g->gc->DumpSet(set);
1980 return errNone;
1983 int prGCSanity(struct VMGlobals *g, int numArgsPushed);
1984 int prGCSanity(struct VMGlobals *g, int numArgsPushed)
1986 g->gc->SanityCheck();
1987 return errNone;
1990 #if GCDEBUG
1991 int prTraceAllPathsTo(struct VMGlobals *g, int numArgsPushed);
1992 int prTraceAllPathsTo(struct VMGlobals *g, int numArgsPushed)
1994 PyrSlot *a = g->sp;
1995 g->gc->TracePathsTo(slotRawObject(a), false);
1996 return errNone;
1999 int prTraceAnyPathsTo(struct VMGlobals *g, int numArgsPushed);
2000 int prTraceAnyPathsTo(struct VMGlobals *g, int numArgsPushed)
2002 PyrSlot *a = g->sp;
2003 g->gc->TracePathsTo(slotRawObject(a), true);
2004 return errNone;
2007 int prTraceAnyPathToAllInstancesOf(struct VMGlobals *g, int numArgsPushed);
2008 int prTraceAnyPathToAllInstancesOf(struct VMGlobals *g, int numArgsPushed)
2010 PyrSlot *a = g->sp;
2011 g->gc->TraceAnyPathToAllInstancesOf(slotRawClass(a)->name.us);
2012 return errNone;
2014 #endif
2016 extern PyrClass *gClassList;
2018 int prAllClasses(struct VMGlobals *g, int numArgsPushed)
2020 PyrSlot *a;
2021 PyrClass *classobj;
2022 PyrObject *array;
2023 int i;
2025 a = g->sp;
2027 array = newPyrArray(g->gc, gNumClasses, 0, true);
2028 classobj = gClassList;
2029 for (i=0; classobj; ++i) {
2030 SetObject(array->slots + i, classobj);
2031 classobj = slotRawClass(&classobj->nextclass);
2033 array->size = gNumClasses;
2034 SetObject(a, array);
2035 return errNone;
2038 int prPostClassTree(struct VMGlobals *g, int numArgsPushed)
2040 PyrSlot *a;
2042 a = g->sp;
2043 postClassTree(slotRawClass(a), 0);
2044 return errNone;
2047 int prDumpBackTrace(struct VMGlobals *g, int numArgsPushed)
2049 PyrSlot *a;
2051 a = g->sp;
2052 DumpBackTrace(g);
2053 return errNone;
2056 /* the DebugFrameConstructor uses a work queue in order to avoid recursions, which could lead to stack overflows */
2057 struct DebugFrameConstructor
2059 void makeDebugFrame (VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot)
2061 workQueue.push_back(std::make_pair(frame, outSlot));
2062 run_queue(g);
2065 private:
2066 void run_queue(VMGlobals *g)
2068 while (!workQueue.empty()) {
2069 WorkQueueItem work = workQueue.back();
2070 workQueue.pop_back();
2071 fillDebugFrame(g, work.first, work.second);
2075 void fillDebugFrame(VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot)
2077 PyrMethod *meth = slotRawMethod(&frame->method);
2078 PyrMethodRaw * methraw = METHRAW(meth);
2080 PyrObject* debugFrameObj = instantiateObject(g->gc, getsym("DebugFrame")->u.classobj, 0, false, true);
2081 SetObject(outSlot, debugFrameObj);
2083 SetObject(debugFrameObj->slots + 0, meth);
2084 SetPtr(debugFrameObj->slots + 5, meth);
2086 int numargs = methraw->numargs;
2087 int numvars = methraw->numvars;
2088 if (numargs) {
2089 PyrObject* argArray = (PyrObject*)newPyrArray(g->gc, numargs, 0, false);
2090 SetObject(debugFrameObj->slots + 1, argArray);
2091 for (int i=0; i<numargs; ++i)
2092 slotCopy(&argArray->slots[i], &frame->vars[i]);
2094 argArray->size = numargs;
2095 } else
2096 SetNil(debugFrameObj->slots + 1);
2098 if (numvars) {
2099 PyrObject* varArray = (PyrObject*)newPyrArray(g->gc, numvars, 0, false);
2100 SetObject(debugFrameObj->slots + 2, varArray);
2101 for (int i=0, j=numargs; i<numvars; ++i,++j)
2102 slotCopy(&varArray->slots[i], &frame->vars[j]);
2104 varArray->size = numvars;
2105 } else
2106 SetNil(debugFrameObj->slots + 2);
2108 if (slotRawFrame(&frame->caller)) {
2109 WorkQueueItem newWork = std::make_pair(slotRawFrame(&frame->caller), debugFrameObj->slots + 3);
2110 workQueue.push_back(newWork);
2111 } else
2112 SetNil(debugFrameObj->slots + 3);
2114 if (IsObj(&frame->context) && slotRawFrame(&frame->context) == frame)
2115 SetObject(debugFrameObj->slots + 4, debugFrameObj);
2116 else if (NotNil(&frame->context)) {
2117 WorkQueueItem newWork = std::make_pair(slotRawFrame(&frame->context), debugFrameObj->slots + 4);
2118 workQueue.push_back(newWork);
2119 } else
2120 SetNil(debugFrameObj->slots + 4);
2123 typedef std::pair<PyrFrame*, PyrSlot*> WorkQueueItem;
2124 typedef std::vector<WorkQueueItem> WorkQueueType;
2125 WorkQueueType workQueue;
2128 static void MakeDebugFrame(VMGlobals *g, PyrFrame *frame, PyrSlot *outSlot)
2130 DebugFrameConstructor constructor;
2131 constructor.makeDebugFrame(g, frame, outSlot);
2134 int prGetBackTrace(VMGlobals *g, int numArgsPushed);
2135 int prGetBackTrace(VMGlobals *g, int numArgsPushed)
2137 PyrSlot *a;
2139 a = g->sp;
2140 MakeDebugFrame(g, g->frame, a);
2142 return errNone;
2145 int prObjectShallowCopy(struct VMGlobals *g, int numArgsPushed)
2147 PyrSlot *a;
2149 a = g->sp;
2150 switch (GetTag(a)) {
2151 case tagObj :
2152 SetRaw(a, copyObject(g->gc, slotRawObject(a), true));
2153 break;
2154 // the default case is to leave the argument unchanged on the stack
2156 return errNone;
2159 int prObjectCopyImmutable(struct VMGlobals *g, int numArgsPushed);
2160 int prObjectCopyImmutable(struct VMGlobals *g, int numArgsPushed)
2162 PyrSlot *a;
2164 a = g->sp;
2165 switch (GetTag(a)) {
2166 case tagObj :
2167 if (slotRawObject(a)->obj_flags & obj_immutable) {
2168 SetRaw(a, copyObject(g->gc, slotRawObject(a), true));
2170 break;
2172 return errNone;
2175 int prObjectIsMutable(struct VMGlobals *g, int numArgsPushed);
2176 int prObjectIsMutable(struct VMGlobals *g, int numArgsPushed)
2178 PyrSlot *a;
2180 a = g->sp;
2181 if (IsObj(a)) {
2182 if (slotRawObject(a)->obj_flags & obj_immutable) {
2183 SetFalse(a);
2184 } else {
2185 SetTrue(a);
2187 } else {
2188 SetFalse(a);
2190 return errNone;
2193 int prObjectIsPermanent(struct VMGlobals *g, int numArgsPushed);
2194 int prObjectIsPermanent(struct VMGlobals *g, int numArgsPushed)
2196 PyrSlot *a;
2198 a = g->sp;
2199 if (IsObj(a)) {
2200 if (slotRawObject(a)->gc_color == obj_permanent) {
2201 SetTrue(a);
2202 } else {
2203 SetFalse(a);
2205 } else {
2206 SetTrue(a);
2208 return errNone;
2213 int prDeepFreeze(struct VMGlobals *g, int numArgsPushed);
2214 int prDeepFreeze(struct VMGlobals *g, int numArgsPushed)
2216 PyrSlot *a;
2218 a = g->sp;
2219 PyrDeepFreezer freezer(g);
2220 int err = freezer.doDeepFreeze(a);
2221 return err;
2225 int prDeepCopy(struct VMGlobals *g, int numArgsPushed);
2226 int prDeepCopy(struct VMGlobals *g, int numArgsPushed)
2228 PyrSlot *a;
2230 a = g->sp;
2231 PyrDeepCopier copier(g);
2232 int err = copier.doDeepCopy(a);
2233 return err;
2239 bool IsSimpleLiteralSlot(PyrSlot* slot);
2240 bool IsSimpleLiteralSlot(PyrSlot* slot)
2242 switch (GetTag(slot)) {
2243 case tagObj : return slotRawObject(slot)->IsPermanent();
2244 case tagInt : return true;
2245 case tagSym : return true;
2246 case tagChar : return true;
2247 case tagNil : return true;
2248 case tagFalse : return true;
2249 case tagTrue : return true;
2250 case tagPtr : return false;
2251 default : return true;
2257 int prObjectCopyRange(struct VMGlobals *g, int numArgsPushed)
2259 PyrSlot *a, *b, *c;
2261 a = g->sp - 2;
2262 b = g->sp - 1;
2263 c = g->sp;
2265 if (NotObj(a)) return errWrongType;
2266 if (NotInt(b)) return errWrongType;
2267 if (NotInt(c)) return errWrongType;
2268 SetRaw(a, copyObjectRange(g->gc, slotRawObject(a), slotRawInt(b), slotRawInt(c), true));
2270 return errNone;
2274 int prObjectCopySeries(struct VMGlobals *g, int numArgsPushed)
2276 PyrSlot *a, *b, *c, *d;
2278 a = g->sp - 3;
2279 b = g->sp - 2;
2280 c = g->sp - 1;
2281 d = g->sp;
2283 PyrObject *inobj = slotRawObject(a);
2284 PyrObject *newobj;
2286 int size = inobj->size;
2287 int flags = ~(obj_immutable) & inobj->obj_flags;
2289 int first, second, last;
2291 if (IsInt(b)) first = slotRawInt(b);
2292 else if (IsNil(b)) first = 0;
2293 else return errWrongType;
2295 if (IsInt(d)) {
2296 last = slotRawInt(d);
2297 if (last < 0 && IsNil(b)) {
2298 zerolength:
2299 newobj = g->gc->New(0, flags, inobj->obj_format, true);
2300 newobj->size = 0;
2301 newobj->classptr = inobj->classptr;
2302 SetRaw(a, newobj);
2303 return errNone;
2305 } else if (IsNil(d)) {
2306 if (first >= size) goto zerolength;
2307 last = size - 1;
2308 } else return errWrongType;
2310 if (IsInt(c)) second = slotRawInt(c);
2311 else if (IsNil(c)) second = first < last ? first + 1 : first - 1;
2312 else return errWrongType;
2314 int step = second - first;
2316 int elemsize = gFormatElemSize[inobj->obj_format];
2317 int length;
2319 if (step > 0) {
2320 length = (last - first) / step + 1;
2321 } else if (step < 0) {
2322 length = (first - last) / -step + 1;
2323 } else return errFailed;
2325 int numbytes = length * elemsize;
2327 newobj = g->gc->New(numbytes, flags, inobj->obj_format, true);
2328 newobj->size = 0;
2329 newobj->classptr = inobj->classptr;
2331 for (int i=first, j=0; j<length; i+=step, ++j) {
2332 PyrSlot slot;
2333 if (i >= 0 && i < inobj->size) {
2334 getIndexedSlot(inobj, &slot, i);
2335 int err = putIndexedSlot(g, newobj, &slot, newobj->size++);
2336 if (err) return err;
2340 SetRaw(a, newobj);
2341 return errNone;
2344 void switchToThread(struct VMGlobals *g, struct PyrThread *newthread, int oldstate, int *numArgsPushed);
2346 int haltInterpreter(struct VMGlobals *g, int numArgsPushed)
2348 switchToThread(g, slotRawThread(&g->process->mainThread), tDone, &numArgsPushed);
2349 // return all the way out.
2350 //PyrSlot *bottom = g->gc->Stack()->slots;
2351 //slotCopy(bottom,g->sp);
2352 //g->sp = bottom; // ??!! pop everybody
2353 g->method = NULL;
2354 g->block = NULL;
2355 g->frame = NULL;
2356 SetNil(g->sp);
2357 longjmp(g->escapeInterpreter, 3);
2358 //hmm need to fix this to work only on main thread. //!!!
2359 //g->sp = g->gc->Stack()->slots - 1;
2361 return errReturn;
2365 int prCanCallOS(struct VMGlobals *g, int numArgsPushed);
2366 int prCanCallOS(struct VMGlobals *g, int numArgsPushed)
2368 PyrSlot *a = g->sp;
2370 SetBool(a, g->canCallOS);
2372 return errNone;
2375 extern bool gGenerateTailCallByteCodes;
2377 int prGetTailCallOptimize(struct VMGlobals *g, int numArgsPushed);
2378 int prGetTailCallOptimize(struct VMGlobals *g, int numArgsPushed)
2380 PyrSlot *a = g->sp;
2382 SetBool(a, gGenerateTailCallByteCodes);
2384 return errNone;
2387 int prSetTailCallOptimize(struct VMGlobals *g, int numArgsPushed);
2388 int prSetTailCallOptimize(struct VMGlobals *g, int numArgsPushed)
2390 //PyrSlot *a = g->sp - 1;
2392 #if TAILCALLOPTIMIZE
2393 PyrSlot *b = g->sp;
2394 if (IsTrue(b)) {
2395 gGenerateTailCallByteCodes = true;
2396 } else if (IsFalse(b)) {
2397 gGenerateTailCallByteCodes = false;
2398 } else return errWrongType;
2399 #endif
2401 return errNone;
2405 int prTraceOn(struct VMGlobals *g, int numArgsPushed);
2406 int prTraceOn(struct VMGlobals *g, int numArgsPushed)
2408 PyrSlot *a;
2410 a = g->sp;
2411 gTraceInterpreter = IsTrue(a);
2412 return errNone;
2415 int prKeywordError(struct VMGlobals *g, int numArgsPushed);
2416 int prKeywordError(struct VMGlobals *g, int numArgsPushed)
2418 PyrSlot *a;
2420 a = g->sp;
2421 gKeywordError = IsTrue(a);
2422 return errNone;
2425 int prFunDef_NumArgs(struct VMGlobals *g, int numArgsPushed);
2426 int prFunDef_NumArgs(struct VMGlobals *g, int numArgsPushed)
2428 PyrSlot *a;
2429 PyrMethodRaw *methraw;
2431 a = g->sp;
2432 methraw = METHRAW(slotRawBlock(a));
2433 SetInt(a, methraw->numargs);
2434 return errNone;
2437 int prFunDef_NumVars(struct VMGlobals *g, int numArgsPushed);
2438 int prFunDef_NumVars(struct VMGlobals *g, int numArgsPushed)
2440 PyrSlot *a;
2441 PyrMethodRaw *methraw;
2443 a = g->sp;
2444 methraw = METHRAW(slotRawBlock(a));
2445 SetInt(a, methraw->numvars);
2446 return errNone;
2449 int prFunDef_VarArgs(struct VMGlobals *g, int numArgsPushed);
2450 int prFunDef_VarArgs(struct VMGlobals *g, int numArgsPushed)
2452 PyrSlot *a;
2453 PyrMethodRaw *methraw;
2455 a = g->sp;
2456 methraw = METHRAW(slotRawBlock(a));
2457 if (methraw->varargs) { SetTrue(a); } else { SetFalse(a); }
2458 return errNone;
2462 int undefinedPrimitive(struct VMGlobals *g, int numArgsPushed)
2464 error("A primitive was not bound. %d %d\n", g->primitiveIndex, gPrimitiveTable.size);
2465 dumpObject((PyrObject*)g->primitiveMethod);
2466 return errFailed;
2469 void dumpByteCodes(PyrBlock *theBlock);
2471 int prDumpByteCodes(struct VMGlobals *g, int numArgsPushed)
2473 PyrSlot *a;
2475 a = g->sp;
2476 dumpByteCodes(slotRawBlock(a));
2477 return errNone;
2480 int prObjectPointsTo(struct VMGlobals *g, int numArgsPushed)
2482 PyrSlot *a, *b, temp;
2483 PyrObject *obj;
2484 int i;
2486 a = g->sp - 1;
2487 b = g->sp;
2489 if (NotObj(a)) slotCopy(a,&o_false);
2490 else {
2491 obj = slotRawObject(a);
2492 for (i=0; i<obj->size; ++i) {
2493 getIndexedSlot(obj, &temp, i);
2494 if (SlotEq(&temp, b)) {
2495 slotCopy(a,&o_true);
2496 return errNone;
2499 slotCopy(a,&o_false);
2501 return errNone;
2505 int prObjectRespondsTo(struct VMGlobals *g, int numArgsPushed)
2507 PyrSlot *a, *b;
2508 PyrClass *classobj;
2509 PyrMethod *meth;
2510 PyrSymbol *selector;
2511 int index;
2513 a = g->sp - 1;
2514 b = g->sp;
2516 classobj = classOfSlot(a);
2518 if (IsSym(b)) {
2520 selector = slotRawSymbol(b);
2521 index = slotRawInt(&classobj->classIndex) + selector->u.index;
2522 meth = gRowTable[index];
2523 if (slotRawSymbol(&meth->name) != selector) {
2524 slotCopy(a,&o_false);
2525 } else {
2526 slotCopy(a,&o_true);
2528 } else if (isKindOfSlot(b, class_array)) {
2529 int size = slotRawObject(b)->size;
2530 PyrSlot *slot = slotRawObject(b)->slots;
2531 for (int i=0; i<size; ++i, ++slot) {
2533 if (NotSym(slot)) return errWrongType;
2535 selector = slotRawSymbol(slot);
2536 index = slotRawInt(&classobj->classIndex) + selector->u.index;
2537 meth = gRowTable[index];
2538 if (slotRawSymbol(&meth->name) != selector) {
2539 slotCopy(a,&o_false);
2540 return errNone;
2543 slotCopy(a,&o_true);
2544 } else return errWrongType;
2545 return errNone;
2548 PyrMethod* GetFunctionCompileContext(VMGlobals* g);
2549 PyrMethod* GetFunctionCompileContext(VMGlobals* g)
2551 PyrClass *classobj;
2552 PyrSymbol *classsym, *contextsym;
2553 PyrMethod *meth;
2554 // lookup interpreter class
2555 classsym = getsym("Interpreter");
2556 classobj = classsym->u.classobj;
2557 if (!classobj) {
2558 error("There is no Interpreter class.\n");
2559 return 0;
2561 // lookup functionCompileContext method
2562 contextsym = getsym("functionCompileContext");
2563 int index = slotRawInt(&classobj->classIndex) + contextsym->u.index;
2564 meth = gRowTable[index];
2565 if (!meth || slotRawSymbol(&meth->name) != contextsym) {
2566 error("compile context method 'functionCompileContext' not found.\n");
2567 return 0;
2569 gCompilingClass = classobj;
2570 gCompilingMethod = meth;
2571 gCompilingBlock = (PyrBlock*)meth;
2572 return meth;
2575 #if !SCPLAYER
2576 int prCompileString(struct VMGlobals *g, int numArgsPushed)
2578 PyrSlot *a, *b;
2579 PyrString *string;
2580 PyrMethod *meth;
2582 a = g->sp - 1;
2583 b = g->sp;
2585 // check b is a string
2586 if (NotObj(b)) return errWrongType;
2587 if (!isKindOf(slotRawObject(b), class_string)) return errWrongType;
2588 string = slotRawString(b);
2590 gRootParseNode = NULL;
2591 initParserPool();
2592 //assert(g->gc->SanityCheck());
2593 startLexerCmdLine(string->s, string->size);
2594 compileErrors = 0;
2595 compilingCmdLine = true;
2596 gCompilingVMGlobals = g;
2597 compilingCmdLineErrorWindow = false;
2598 //assert(g->gc->SanityCheck());
2599 parseFailed = yyparse();
2600 //assert(g->gc->SanityCheck());
2601 if (!parseFailed && gRootParseNode) {
2602 PyrSlot slotResult;
2604 meth = GetFunctionCompileContext(g);
2605 if (!meth) return errFailed;
2607 ((PyrBlockNode*)gRootParseNode)->mIsTopLevel = true;
2609 SetNil(&slotResult);
2610 COMPILENODE(gRootParseNode, &slotResult, true);
2612 if (NotObj(&slotResult)
2613 || slotRawObject(&slotResult)->classptr != class_fundef) {
2614 compileErrors++;
2615 error("Compile did not return a FunctionDef..\n");
2617 if (compileErrors) {
2618 SetNil(a);
2619 } else {
2620 PyrBlock *block;
2621 PyrClosure *closure;
2623 block = slotRawBlock(&slotResult);
2624 // create a closure
2625 closure = (PyrClosure*)g->gc->New(2*sizeof(PyrSlot), 0, obj_notindexed, false);
2626 closure->classptr = class_func;
2627 closure->size = 2;
2628 SetObject(&closure->block, block);
2629 slotCopy(&closure->context,&slotRawInterpreter(&g->process->interpreter)->context);
2630 SetObject(a, closure);
2632 } else {
2633 if (parseFailed) {
2634 compileErrors++;
2635 error("Command line parse failed\n");
2636 } else {
2637 postfl("<nothing to do>\n");
2639 SetNil(a);
2641 finiLexer();
2642 freeParserPool();
2644 pyr_pool_compile->FreeAll();
2645 //flushErrors();
2646 compilingCmdLine = false;
2648 return !(parseFailed || compileErrors) ? errNone : errFailed;
2650 #endif
2652 char sCodeStringIn[8192];
2653 char sCodeStringOut[8192];
2655 int prUGenCodeString(struct VMGlobals *g, int numArgsPushed);
2656 int prUGenCodeString(struct VMGlobals *g, int numArgsPushed)
2658 PyrSlot *aa, *bb, *cc, *dd, *ee;
2659 char *out = sCodeStringOut;
2660 char ugenPrefix[16];
2661 int err;
2663 aa = g->sp - 4; // code string
2664 bb = g->sp - 3; // ugen prefix
2665 ee = g->sp - 2; // isDecl
2666 cc = g->sp - 1; // input names
2667 dd = g->sp; // input value strings
2669 int ugenIndex;
2670 err = slotIntVal(bb, &ugenIndex);
2671 if (err) return err;
2672 if (!isKindOfSlot(cc, class_array) && !isKindOfSlot(cc, class_symbolarray)) return errWrongType;
2673 if (!isKindOfSlot(dd, class_array)) return errWrongType;
2674 bool isDecl = IsTrue(ee);
2676 PyrObject *inputNamesObj = slotRawObject(cc);
2677 PyrObject *inputStringsObj = slotRawObject(dd);
2679 sprintf(ugenPrefix, "u%d", ugenIndex);
2680 int ugenPrefixSize = strlen(ugenPrefix);
2681 PyrString* codeStringObj = slotRawString(aa);
2682 int codeStringSize = codeStringObj->size;
2683 if (codeStringSize > 8000) {
2684 error("input string too int.\n");
2685 return errFailed;
2687 memcpy(sCodeStringIn, codeStringObj->s, codeStringSize);
2688 sCodeStringIn[codeStringSize] = 0;
2690 char* in = sCodeStringIn;
2691 int c;
2692 while ((c = *in++) != 0) {
2693 if (c == '@') {
2694 if (!isDecl) {
2695 if (*in != '@') {
2696 *out++ = 's';
2697 *out++ = '-';
2698 *out++ = '>';
2699 } else in++;
2701 for (int j=0; j<ugenPrefixSize; ++j) {
2702 *out++ = ugenPrefix[j];
2704 } else if (c == '$') {
2705 char name[64];
2706 int j=0;
2707 do {
2708 c = *in++;
2709 if (c == 0) break;
2710 if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))) {
2711 --in;
2712 break;
2714 name[j++] = c;
2715 } while (c);
2717 bool found = false;
2718 int nameSize = j;
2719 int slotIndex = -1;
2720 for (int j=0; j<inputNamesObj->size; ++j) {
2721 PyrSlot inputNameSlot;
2722 getIndexedSlot(inputNamesObj, &inputNameSlot, j);
2723 if (!IsSym(&inputNameSlot)) return errWrongType;
2724 PyrSymbol* inputSym = slotRawSymbol(&inputNameSlot);
2725 char *inputName = inputSym->name;
2726 int inputNameSize = inputSym->length;
2727 if (inputNameSize == nameSize && strncmp(inputName, name, nameSize)==0) {
2728 found = true;
2729 slotIndex = j;
2730 break;
2733 if (slotIndex >= 0) {
2734 PyrSlot *inputStringSlot = inputStringsObj->slots + slotIndex;
2735 if (!isKindOfSlot(inputStringSlot, class_string)) return errWrongType;
2736 PyrString *inputStringObj = slotRawString(inputStringSlot);
2737 char *input = inputStringObj->s;
2738 int inputStringSize = inputStringObj->size;
2739 for (int j=0; j<inputStringSize; ++j) {
2740 *out++ = input[j];
2742 } else {
2743 *out++ = '?'; *out++ = '?';
2744 for (int j=0; j<nameSize; ++j) {
2745 *out++ = name[j];
2747 *out++ = '?'; *out++ = '?';
2749 } else {
2750 *out++ = c;
2752 if (out - sCodeStringOut > 8000) {
2753 *out++ = '\n';
2754 *out++ = '.';
2755 *out++ = '.';
2756 *out++ = '.';
2757 *out++ = '\n';
2758 break;
2761 *out++ = 0;
2762 PyrString* outString = newPyrString(g->gc, sCodeStringOut, 0, true);
2763 SetObject(aa, outString);
2765 return errNone;
2770 /*void threadSanity(VMGlobals *g, PyrThread *thread);
2771 void threadSanity(VMGlobals *g, PyrThread *thread)
2773 int state;
2774 g->gc->numToScan = 1000000;
2775 doGC(g, 0);
2776 assert(g->gc->SanityCheck());
2778 state = slotRawInt(&thread->state);
2779 if (state == tYield) {
2780 if (!IsObj(&thread->method)) { error("thread method not an Object\n"); }
2781 else if (!isKindOf(slotRawObject(&thread->method), class_method)) { error("thread method not a Method\n"); }
2782 else if (slotRawObject(&thread->method)->gc_color == gcColor.gcFree) { error("thread method is FREE\n"); }
2784 if (!IsObj(&thread->block)) { error("thread block not an Object\n"); }
2785 else if (!isKindOf(slotRawObject(&thread->block), class_func)) { error("thread block not a Function\n"); }
2786 else if (slotRawObject(&thread->block)->gc_color == gcColor.gcFree) { error("thread block is FREE\n"); }
2788 if (IsObj(&thread->receiver) &slotRawObject(&& thread->receiver)->gc_color == gcColor.gcFree)
2789 { error("thread receiver is FREE\n"); }
2791 FrameSanity(thread->frame.uof);
2793 oldthread->method.uom = g->method;
2794 oldthread->block.uoblk = g->block;
2795 SetObject(&oldthread->frame, g->frame);
2796 slotRawInt(&oldthread->ip) = (int)g->ip;
2797 slotRawInt(&oldthread->sp) = (int)g->sp;
2800 } else if (state == tInit) {
2801 } else {
2802 postfl("bad state\n");
2807 PyrSymbol *s_prready;
2808 PyrSymbol *s_prrunnextthread;
2810 void switchToThread(VMGlobals *g, PyrThread *newthread, int oldstate, int *numArgsPushed);
2811 void switchToThread(VMGlobals *g, PyrThread *newthread, int oldstate, int *numArgsPushed)
2813 PyrThread *oldthread;
2814 PyrGC *gc;
2815 PyrFrame *frame;
2817 #if TAILCALLOPTIMIZE
2818 g->tailCall = 0; // ?? prevent a crash. is there a way to allow a TCO ?
2819 #endif
2821 oldthread = g->thread;
2822 if (newthread == oldthread) return;
2823 //postfl("->switchToThread %d %p -> %p\n", oldstate, oldthread, newthread);
2824 //post("->switchToThread from %s:%s\n", slotRawClass(&g->method->ownerclass)->name.us->name, g->slotRawSymbol(&method->name)->name);
2825 //post("->stack %p g->sp %p [%d] g->top %p [%d]\n",
2826 // g->gc->Stack()->slots, g->sp, g->sp - g->gc->Stack()->slots, g->top, g->top - g->gc->Stack()->slots);
2827 //assert(g->gc->SanityCheck());
2828 //CallStackSanity(g, "switchToThreadA");
2829 //gcDumpInfo(g->gc);
2830 gc = g->gc;
2832 // save environment in oldthread
2833 PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1];
2834 slotCopy(&oldthread->environment,currentEnvironmentSlot);
2835 gc->GCWrite(oldthread, currentEnvironmentSlot);
2837 SetRaw(&oldthread->state, oldstate);
2839 if (oldstate == tDone) {
2840 SetObject(&oldthread->stack, gc->Stack());
2841 gc->ToWhite(gc->Stack());
2842 gc->Stack()->size = 0;
2843 gc->GCWrite(oldthread, gc->Stack());
2844 SetNil(&oldthread->method);
2845 SetNil(&oldthread->block);
2846 SetNil(&oldthread->receiver);
2847 SetNil(&oldthread->frame);
2848 SetRaw(&oldthread->ip, (void*)0);
2849 SetRaw(&oldthread->sp, (void*)0);
2850 SetRaw(&oldthread->numArgsPushed, 0);
2851 SetRaw(&oldthread->numpop, 0);
2852 SetNil(&oldthread->parent);
2853 } else if (oldstate == tInit) {
2854 SetObject(&oldthread->stack, gc->Stack());
2855 gc->ToWhite(gc->Stack());
2856 gc->Stack()->size = 0;
2857 gc->GCWrite(oldthread, gc->Stack());
2858 SetNil(&oldthread->method);
2859 SetNil(&oldthread->block);
2860 SetNil(&oldthread->receiver);
2861 SetNil(&oldthread->frame);
2862 SetRaw(&oldthread->ip, (void*)0);
2863 SetRaw(&oldthread->sp, (void*)0);
2864 SetRaw(&oldthread->numArgsPushed, 0);
2865 SetRaw(&oldthread->numpop, 0);
2866 SetNil(&oldthread->parent);
2867 } else {
2868 // save old thread's state
2869 SetObject(&oldthread->stack, gc->Stack());
2870 gc->ToWhite(gc->Stack());
2871 gc->Stack()->size = g->sp - gc->Stack()->slots + 1;
2872 //post("else %p %p\n", slotRawObject(&oldthread->stack), gc->Stack());
2874 SetObject(&oldthread->method, g->method);
2875 SetObject(&oldthread->block, g->block);
2876 SetObject(&oldthread->frame, g->frame);
2877 SetPtr(&oldthread->ip, g->ip);
2878 SetPtr(&oldthread->sp, g->sp);
2879 slotCopy(&oldthread->receiver,&g->receiver);
2880 SetRaw(&oldthread->numArgsPushed, *numArgsPushed);
2881 SetRaw(&oldthread->numpop, g->numpop);
2883 //gc->ToGrey(oldthread);
2884 if (gc->ObjIsBlack(oldthread)) {
2885 gc->GCWriteBlack(gc->Stack());
2886 gc->GCWriteBlack(g->method);
2887 gc->GCWriteBlack(g->block);
2889 frame = slotRawFrame(&oldthread->frame);
2890 gc->GCWriteBlack(frame);
2892 gc->GCWriteBlack(&g->receiver);
2896 // restore new thread's state
2897 g->thread = newthread;
2898 SetObject(&g->process->curThread, newthread);
2899 gc->GCWrite(g->process, newthread);
2901 gc->SetStack(slotRawObject(&newthread->stack));
2902 gc->ToBlack(gc->Stack());
2903 SetNil(&newthread->stack);
2905 g->method = slotRawMethod(&newthread->method);
2906 g->block = slotRawBlock(&newthread->block);
2907 g->frame = slotRawFrame(&newthread->frame);
2908 g->ip = (unsigned char *)slotRawPtr(&newthread->ip);
2909 g->sp = (PyrSlot*)slotRawPtr(&newthread->sp);
2910 slotCopy(&g->receiver,&newthread->receiver);
2912 g->rgen = (RGen*)(slotRawObject(&newthread->randData)->slots);
2914 *numArgsPushed = slotRawInt(&newthread->numArgsPushed);
2916 // these are perhaps unecessary because a thread may not
2917 // legally block within a C primitive
2918 g->numpop = slotRawInt(&newthread->numpop);
2920 g->execMethod = 99;
2922 //post("switchToThread ip %p\n", g->ip);
2923 //post(slotRawInt(&"switchToThread newthread->ip) %d\n", slotRawInt(&newthread->ip));
2924 //post(slotRawInt(&"switchToThread oldthread->ip) %d\n", slotRawInt(&oldthread->ip));
2926 // wipe out values which will become stale as new thread executes:
2927 SetNil(&newthread->method);
2928 SetNil(&newthread->block);
2929 SetNil(&newthread->frame);
2930 SetRaw(&newthread->ip, (void*)0);
2931 SetRaw(&newthread->sp, (void*)0);
2932 SetNil(&newthread->receiver);
2934 SetRaw(&newthread->state, tRunning);
2937 // set new environment
2938 slotCopy(currentEnvironmentSlot,&g->thread->environment);
2939 g->gc->GCWrite(g->classvars, currentEnvironmentSlot);
2941 //post("old thread %p stack %p\n", oldthread, slotRawObject(&oldthread->stack));
2942 //post("new thread %p stack %p\n", g->thread, slotRawObject(&g->thread->stack));
2943 //post("main thread %p stack %p\n", slotRawThread(&g->process->mainThread), slotRawObject(&slotRawThread(&g->process->mainThread)->stack));
2945 //postfl("<-switchToThread\n");
2946 //post("<-stack %p g->sp %p [%d] g->top %p [%d]\n",
2947 // g->gc->Stack()->slots, g->sp, g->sp - g->gc->Stack()->slots, g->top, g->top - g->gc->Stack()->slots);
2948 //assert(g->gc->SanityCheck());
2949 //CallStackSanity(g, "switchToThreadB");
2950 //post("switchToThread ip2 %p\n", g->ip);
2953 void initPyrThread(VMGlobals *g, PyrThread *thread, PyrSlot *func, int stacksize, PyrInt32Array* rgenArray,
2954 double beats, double seconds, PyrSlot* clock, bool collect);
2955 void initPyrThread(VMGlobals *g, PyrThread *thread, PyrSlot *func, int stacksize, PyrInt32Array* rgenArray,
2956 double beats, double seconds, PyrSlot* clock, bool collect)
2958 PyrObject *array;
2959 PyrGC* gc = g->gc;
2961 slotCopy(&thread->func, func);
2962 gc->GCWrite(thread, func);
2964 array = newPyrArray(gc, stacksize, 0, collect);
2965 SetObject(&thread->stack, array);
2966 gc->GCWrite(thread, array);
2968 SetInt(&thread->state, tInit);
2970 SetPtr(&thread->ip, 0);
2971 SetPtr(&thread->sp, 0);
2973 SetObject(&thread->randData, rgenArray);
2974 gc->GCWrite(thread, rgenArray);
2976 SetFloat(&thread->beats, beats);
2977 SetFloat(&thread->seconds, seconds);
2978 SetInt(&thread->numArgsPushed, 0);
2979 SetInt(&thread->numpop, 0);
2981 if (IsNil(clock)) {
2982 SetObject(&thread->clock, s_systemclock->u.classobj);
2983 } else {
2984 slotCopy(&thread->clock,clock);
2985 gc->GCWrite(thread, clock);
2988 PyrSlot* currentEnvironmentSlot = &g->classvars->slots[1];
2989 slotCopy(&thread->environment,currentEnvironmentSlot);
2990 gc->GCWrite(thread, currentEnvironmentSlot);
2992 if(g->process) { // check we're not just starting up
2993 slotCopy(&thread->executingPath,&g->process->nowExecutingPath);
2994 gc->GCWrite(thread, &g->process->nowExecutingPath);
2997 SetInt(&thread->stackSize, stacksize);
3000 extern PyrSymbol *s_prstart;
3002 int prThreadInit(struct VMGlobals *g, int numArgsPushed);
3003 int prThreadInit(struct VMGlobals *g, int numArgsPushed)
3005 PyrSlot *a, *b, *c;
3006 int stacksize, err;
3007 PyrThread *thread;
3009 //postfl("->prThreadInit\n");
3010 //assert(g->gc->SanityCheck());
3011 //CallStackSanity(g, "prThreadInit");
3012 a = g->sp - 2; // thread
3013 b = g->sp - 1; // function
3014 c = g->sp; // stacksize
3016 thread = slotRawThread(a);
3018 if (NotObj(b) || !isKindOf(slotRawObject(b), class_func)) {
3019 error("Thread function arg not a Function.\n");
3020 return errWrongType;
3023 err = slotIntVal(c, &stacksize);
3024 if (err) return err;
3026 stacksize = std::max(stacksize, EVALSTACKDEPTH);
3028 initPyrThread(g, thread, b, stacksize, (PyrInt32Array*)(slotRawObject(&g->thread->randData)),
3029 slotRawFloat(&g->thread->beats), slotRawFloat(&g->thread->seconds), &g->thread->clock, true);
3031 //postfl("<-prThreadInit\n");
3032 //assert(g->gc->SanityCheck());
3033 //CallStackSanity(g, "<prThreadInit");
3034 return errNone;
3037 int prThreadRandSeed(struct VMGlobals *g, int numArgsPushed);
3038 int prThreadRandSeed(struct VMGlobals *g, int numArgsPushed)
3040 PyrSlot *a = g->sp - 1; // thread
3041 PyrSlot *b = g->sp; // rand seed
3043 PyrThread *thread = slotRawThread(a);
3045 int32 seed;
3046 int err = slotIntVal(b, &seed);
3047 if (err) return err;
3049 PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, true);
3050 rgenArray->size = 4;
3051 ((RGen*)(rgenArray->i))->init(seed);
3053 if (thread == g->thread) {
3054 g->rgen = (RGen*)(rgenArray->i);
3056 SetObject(&thread->randData, rgenArray);
3057 g->gc->GCWrite(thread, rgenArray);
3059 return errNone;
3062 int prThreadGetRandData(struct VMGlobals *g, int numArgsPushed);
3063 int prThreadGetRandData(struct VMGlobals *g, int numArgsPushed)
3065 PyrSlot *a = g->sp; // thread
3067 PyrThread *thread = slotRawThread(a);
3069 RGen* rgen = (RGen*)slotRawObject(&thread->randData)->slots;
3071 PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, false);
3072 rgenArray->size = 3;
3074 rgenArray->i[0] = rgen->s1;
3075 rgenArray->i[1] = rgen->s2;
3076 rgenArray->i[2] = rgen->s3;
3078 SetObject(a, rgenArray);
3079 return errNone;
3082 int prThreadSetRandData(struct VMGlobals *g, int numArgsPushed);
3083 int prThreadSetRandData(struct VMGlobals *g, int numArgsPushed)
3085 PyrSlot *a = g->sp - 1; // thread
3086 PyrSlot *b = g->sp; // rand data array
3088 if (!isKindOfSlot(b, class_int32array)) return errWrongType;
3089 if (slotRawObject(b)->size < 3) return errWrongType;
3091 PyrThread *thread = slotRawThread(a);
3093 RGen* rgen = (RGen*)slotRawObject(&thread->randData)->slots;
3095 PyrInt32Array *rgenArray = (PyrInt32Array*)slotRawObject(b);
3097 rgen->s1 = rgenArray->i[0];
3098 rgen->s2 = rgenArray->i[1];
3099 rgen->s3 = rgenArray->i[2];
3101 return errNone;
3104 #if 0
3105 int32 timeseed();
3107 int transformMainThreadToRoutine(VMGlobals *g)
3109 PyrProcess* process = g->process;
3110 if (g->thread != process->mainThread.uot) return errFailed;
3111 //if (g->thread != process->curThread.uot) return errFailed;
3113 PyrThread* curthread = (PyrThread*)slotRawObject(&process->mainThread);
3115 // create a new main thread
3116 PyrThread* newthread = (PyrThread*)instantiateObject(g->gc, class_thread, 0, true, false);
3118 PyrInt32Array *rgenArray = newPyrInt32Array(g->gc, 4, 0, false);
3119 rgenArray->size = 4;
3120 ((RGen*)(rgenArray->i))->init(timeseed());
3122 PyrSlot clockSlot;
3123 SetObject(&clockSlot, s_systemclock->u.classobj);
3124 initPyrThread(g, newthread, &o_nil, EVALSTACKDEPTH, rgenArray, 0., 0., &clockSlot, false);
3125 slotRawInt(&newthread->sp) = (int)slotRawObject(&newthread->stack)->slots - 1;
3126 SetObject(&process->mainThread, newthread);
3127 g->gc->GCWrite(process, newthread);
3129 curthread->classptr = class_routine;
3130 PyrSlot *cmdFunc = &process->interpreter.uoi->cmdFunc;
3131 slotCopy(&curthread->func,cmdFunc);
3132 g->gc->GCWrite(curthread, cmdFunc);
3134 return errNone;
3137 void schedAdd(VMGlobals *g, PyrObject* inQueue, double inSeconds, PyrSlot* inTask);
3138 #endif
3141 int prRoutineYield(struct VMGlobals *g, int numArgsPushed);
3142 int prRoutineYield(struct VMGlobals *g, int numArgsPushed)
3144 PyrSlot value;
3146 //postfl("->prRoutineYield %p\n", g->thread);
3147 //assert(g->gc->SanityCheck());
3148 //CallStackSanity(g, "prRoutineYield");
3149 //postfl("->numArgsPushed %d\n", numArgsPushed);
3151 slotCopy(&value,g->sp);
3153 if (!isKindOf((PyrObject*)g->thread, class_routine)) {
3154 error ("yield was called outside of a Routine.\n");
3155 return errFailed;
3158 PyrThread *parent = slotRawThread(&g->thread->parent);
3159 SetNil(&g->thread->parent);
3160 slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath);
3161 //debugf("yield from thread %p to parent %p\n", g->thread, slotRawThread(&g->thread->parent));
3162 switchToThread(g, parent, tSuspended, &numArgsPushed);
3164 // on the other side of the looking glass, put the yielded value on the stack as the result..
3165 slotCopy((g->sp - numArgsPushed + 1),&value);
3167 //postfl("<-numArgsPushed %d\n", numArgsPushed);
3168 //postfl("<-prRoutineYield\n");
3169 //assert(g->gc->SanityCheck());
3170 //CallStackSanity(g, "<prRoutineYield");
3171 return errNone;
3174 int prRoutineAlwaysYield(struct VMGlobals *g, int numArgsPushed);
3175 int prRoutineAlwaysYield(struct VMGlobals *g, int numArgsPushed)
3177 PyrSlot value;
3179 //postfl("->prRoutineAlwaysYield ip %p\n", g->ip);
3180 //assert(g->gc->SanityCheck());
3181 //CallStackSanity(g, "prRoutineAlwaysYield");
3182 if (!isKindOf((PyrObject*)g->thread, class_routine)) {
3183 error ("alwaysYield was called outside of a Routine.\n");
3184 return errFailed;
3187 slotCopy(&value,g->sp);
3188 slotCopy(&g->thread->terminalValue,&value);
3189 g->gc->GCWrite(g->thread, g->sp);
3191 PyrThread *parent = slotRawThread(&g->thread->parent);
3192 SetNil(&g->thread->parent);
3193 slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath);
3194 //post("alwaysYield from thread %p to parent %p\n", g->thread, parent);
3195 switchToThread(g, parent, tDone, &numArgsPushed);
3197 // on the other side of the looking glass, put the yielded value on the stack as the result..
3198 slotCopy((g->sp - numArgsPushed + 1),&value);
3200 //postfl("<-prRoutineAlwaysYield ip %p\n", g->ip);
3201 //assert(g->gc->SanityCheck());
3202 //CallStackSanity(g, "<prRoutineAlwaysYield");
3203 return errNone;
3206 int prRoutineResume(struct VMGlobals *g, int numArgsPushed);
3207 int prRoutineResume(struct VMGlobals *g, int numArgsPushed)
3209 PyrSlot *a, *b, threadSlot, value;
3210 PyrThread *thread;
3211 int state;
3213 //assert(g->gc->SanityCheck());
3214 //CallStackSanity(g, "prRoutineResume");
3215 a = g->sp - 1;
3216 b = g->sp;
3218 thread = slotRawThread(a);
3219 state = slotRawInt(&thread->state);
3220 //postfl("->prRoutineResume %d\n", state);
3222 slotCopy(&thread->oldExecutingPath,&g->process->nowExecutingPath);
3223 slotCopy(&g->process->nowExecutingPath, &thread->executingPath);
3224 if (state == tInit) {
3225 slotCopy(&threadSlot,a);
3226 slotCopy(&value,b);
3228 //post("g->thread %p\n", g->thread);
3229 //post("thread %p\n", thread);
3230 SetObject(&thread->parent, g->thread);
3231 g->gc->GCWrite(thread, g->thread);
3233 SetRaw(&thread->beats, slotRawFloat(&g->thread->beats));
3234 SetRaw(&thread->seconds, slotRawFloat(&g->thread->seconds));
3235 slotCopy(&thread->clock, &g->thread->clock);
3236 g->gc->GCWrite(thread, &g->thread->clock);
3238 //postfl("start into thread %p from parent %p\n", thread, g->thread);
3239 switchToThread(g, thread, tSuspended, &numArgsPushed);
3241 // set stack
3242 //post("set stack %p %p\n", g->sp, g->gc->Stack()->slots - 1);
3243 g->sp = g->gc->Stack()->slots - 1;
3244 slotCopy((++g->sp), &threadSlot);
3245 slotCopy(&g->receiver, &threadSlot);
3246 slotCopy((++g->sp),&value);
3248 sendMessage(g, s_prstart, 2);
3249 } else if (state == tSuspended) {
3251 if (IsNil(&thread->parent)) {
3252 SetObject(&thread->parent, g->thread);
3254 g->gc->GCWrite(thread, g->thread);
3256 SetRaw(&thread->beats, slotRawFloat(&g->thread->beats));
3257 SetRaw(&thread->seconds, slotRawFloat(&g->thread->seconds));
3258 slotCopy(&thread->clock,&g->thread->clock);
3259 g->gc->GCWrite(thread, &g->thread->clock);
3261 slotCopy(&value,b);
3262 //debugf("resume into thread %p from parent %p\n", thread, g->thread);
3263 switchToThread(g, thread, tSuspended, &numArgsPushed);
3264 // on the other side of the looking glass, put the yielded value on the stack as the result..
3265 slotCopy((g->sp - numArgsPushed + 1),&value);
3266 } else if (state == tDone) {
3267 slotCopy(a,&thread->terminalValue);
3268 } else if (state == tRunning) {
3269 error("Tried to resume the running thread.\n");
3270 return errFailed;
3271 } else {
3272 error("Thread in strange state: %d\n", state);
3273 return errFailed;
3275 //postfl("<-prRoutineResume\n");
3276 //CallStackSanity(g);
3277 return errNone;
3280 int prRoutineReset(struct VMGlobals *g, int numArgsPushed);
3281 int prRoutineReset(struct VMGlobals *g, int numArgsPushed)
3283 PyrThread *thread;
3284 int state;
3286 //assert(g->gc->SanityCheck());
3287 //CallStackSanity(g, "prRoutineReset");
3288 thread = slotRawThread(g->sp);
3289 state = slotRawInt(&thread->state);
3290 //post("->prRoutineReset %d\n", state);
3291 if (state == tSuspended) {
3292 SetRaw(&thread->state, tInit);
3293 slotRawObject(&thread->stack)->size = 0;
3294 SetNil(&thread->method);
3295 SetNil(&thread->block);
3296 SetNil(&thread->receiver);
3297 SetNil(&thread->frame);
3298 SetRaw(&thread->ip, (void*)0);
3299 SetRaw(&thread->sp, (void*)0);
3300 SetRaw(&thread->numArgsPushed, 0);
3301 SetRaw(&thread->numpop, 0);
3302 SetNil(&thread->parent);
3303 } else if (state == tDone) {
3304 SetRaw(&thread->state, tInit);
3305 slotRawObject(&thread->stack)->size = 0;
3306 SetNil(&thread->method);
3307 SetNil(&thread->block);
3308 SetNil(&thread->receiver);
3309 SetNil(&thread->frame);
3310 SetRaw(&thread->ip, (void*)0);
3311 SetRaw(&thread->sp, (void*)0);
3312 SetRaw(&thread->numArgsPushed, 0);
3313 SetRaw(&thread->numpop, 0);
3314 SetNil(&thread->parent);
3315 } else if (state == tInit) {
3316 // do nothing
3317 } else if (state == tRunning) {
3318 error("A Routine cannot reset itself except by yieldAndReset.\n");
3319 return errFailed;
3320 } else {
3321 error("Routine in unknown state. %d\n", state);
3322 return errFailed;
3324 //assert(g->gc->SanityCheck());
3325 //CallStackSanity(g, "<prRoutineReset");
3326 return errNone;
3329 int prRoutineStop(struct VMGlobals *g, int numArgsPushed);
3330 int prRoutineStop(struct VMGlobals *g, int numArgsPushed)
3332 PyrThread *thread;
3333 int state;
3334 //post("->prRoutineStop\n");
3335 //assert(g->gc->SanityCheck());
3336 //CallStackSanity(g, "prRoutineStop");
3338 thread = slotRawThread(g->sp);
3339 state = slotRawInt(&thread->state);
3342 if (state == tSuspended || state == tInit) {
3343 slotCopy(&g->process->nowExecutingPath, &thread->oldExecutingPath);
3344 SetNil(&g->thread->terminalValue);
3345 SetRaw(&thread->state, tDone);
3346 slotRawObject(&thread->stack)->size = 0;
3347 } else if (state == tDone) {
3348 // do nothing
3349 } else if (state == tRunning) {
3350 error("Do not call .stop from within the Routine.\n");
3351 post("A Routine should stop itself using nil.alwaysYield.\n");
3352 return errFailed;
3353 } else {
3354 error("Routine in unknown state. %d\n", state);
3355 return errFailed;
3357 //assert(g->gc->SanityCheck());
3358 //CallStackSanity(g, "<prRoutineStop");
3359 return errNone;
3363 int prRoutineYieldAndReset(struct VMGlobals *g, int numArgsPushed);
3364 int prRoutineYieldAndReset(struct VMGlobals *g, int numArgsPushed)
3366 PyrSlot *a, *b, value;
3367 int state;
3369 //post("->prRoutineYieldAndReset\n");
3370 //assert(g->gc->SanityCheck());
3371 //CallStackSanity(g, "prRoutineYieldAndReset");
3372 a = g->sp - 1;
3373 b = g->sp;
3375 if (!isKindOf((PyrObject*)g->thread, class_routine)) {
3376 error ("yieldAndReset was called outside of a Routine.\n");
3377 return errFailed;
3379 /*if (!slotRawThread(&g->thread->parent)) {
3380 error ("yieldAndReset was called from a thread with no parent.\n");
3381 return errFailed;
3383 slotCopy(&value,a);
3385 if (IsFalse(b)) state = tSuspended;
3386 else state = tInit;
3388 PyrThread *parent = slotRawThread(&g->thread->parent);
3389 SetNil(&g->thread->parent);
3390 switchToThread(g, parent, state, &numArgsPushed);
3391 // on the other side of the looking glass, put the yielded value on the stack as the result..
3392 slotCopy((g->sp - numArgsPushed + 1),&value);
3394 //slotCopy(&g->process->nowExecutingPath, &g->thread->oldExecutingPath);
3396 //post("<-prRoutineYieldAndReset\n");
3397 //assert(g->gc->SanityCheck());
3398 //CallStackSanity(g, "prRoutineYieldAndReset");
3399 return errNone;
3403 bool gBlork = false;
3405 int prBlork(struct VMGlobals *g, int numArgsPushed);
3406 int prBlork(struct VMGlobals *g, int numArgsPushed)
3408 PyrSlot *a;
3410 a = g->sp;
3411 if (IsTrue(a)) gBlork = true;
3412 else gBlork = false;
3414 return errNone;
3417 int prOverwriteMsg(struct VMGlobals *g, int numArgsPushed);
3418 int prOverwriteMsg(struct VMGlobals *g, int numArgsPushed)
3420 PyrSlot *a = g->sp;
3421 PyrString* string = newPyrString(g->gc, overwriteMsg.c_str(), 0, false);
3422 SetObject(a, string);
3423 return errNone;
3426 int prAppClockSchedNotify(struct VMGlobals *g, int numArgsPushed)
3428 //NOTE: the _AppClock_SchedNotify primitive shall be redefined by language clients
3429 // if they wish to respond to AppClock scheduling notifications
3430 return errNone;
3433 enum {includePaths, excludePaths};
3435 static int prLanguageConfig_getLibraryPaths(struct VMGlobals * g, int numArgsPushed, int pathType)
3437 PyrSlot *result = g->sp;
3439 typedef SC_LanguageConfig::DirVector DirVector;
3441 DirVector const & dirVector = (pathType == includePaths) ? gLibraryConfig->includedDirectories()
3442 : gLibraryConfig->excludedDirectories();
3444 size_t numberOfPaths = dirVector.size();
3445 PyrObject * resultArray = newPyrArray(g->gc, numberOfPaths, 0, true);
3446 SetObject(result, resultArray);
3447 resultArray->size = numberOfPaths;
3449 for (size_t i = 0; i != numberOfPaths; ++i)
3450 SetObject(resultArray->slots + i, newPyrString(g->gc, dirVector[i].c_str(), 0, true));
3451 return errNone;
3454 static int prLanguageConfig_getIncludePaths(struct VMGlobals * g, int numArgsPushed)
3456 return prLanguageConfig_getLibraryPaths(g, numArgsPushed, includePaths);
3459 static int prLanguageConfig_getExcludePaths(struct VMGlobals * g, int numArgsPushed)
3461 return prLanguageConfig_getLibraryPaths(g, numArgsPushed, excludePaths);
3464 static int prLanguageConfig_addLibraryPath(struct VMGlobals * g, int numArgsPushed, int pathType)
3466 PyrSlot *removeString = g->sp;
3468 char path[MAXPATHLEN];
3469 bool error = slotStrVal(removeString, path, MAXPATHLEN);
3470 if (error)
3471 return errWrongType;
3473 if (pathType == includePaths)
3474 gLibraryConfig->addIncludedDirectory(path);
3475 else
3476 gLibraryConfig->addExcludedDirectory(path);
3477 return errNone;
3480 static int prLanguageConfig_addIncludePath(struct VMGlobals * g, int numArgsPushed)
3482 return prLanguageConfig_addLibraryPath(g, numArgsPushed, includePaths);
3485 static int prLanguageConfig_addExcludePath(struct VMGlobals * g, int numArgsPushed)
3487 return prLanguageConfig_addLibraryPath(g, numArgsPushed, excludePaths);
3490 static int prLanguageConfig_removeLibraryPath(struct VMGlobals * g, int numArgsPushed, int pathType)
3492 PyrSlot *dirString = g->sp;
3494 char path[MAXPATHLEN];
3495 bool error = slotStrVal(dirString, path, MAXPATHLEN);
3496 if (error)
3497 return errWrongType;
3499 if (pathType == includePaths)
3500 gLibraryConfig->removeIncludedDirectory(path);
3501 else
3502 gLibraryConfig->removeExcludedDirectory(path);
3503 return errNone;
3506 static int prLanguageConfig_removeIncludePath(struct VMGlobals * g, int numArgsPushed)
3508 return prLanguageConfig_removeLibraryPath(g, numArgsPushed, includePaths);
3511 static int prLanguageConfig_removeExcludePath(struct VMGlobals * g, int numArgsPushed)
3513 return prLanguageConfig_removeLibraryPath(g, numArgsPushed, excludePaths);
3516 static int prLanguageConfig_writeConfigFile(struct VMGlobals * g, int numArgsPushed)
3518 PyrSlot *fileString = g->sp;
3520 char path[MAXPATHLEN];
3521 if (NotNil(fileString)) {
3522 bool error = slotStrVal(fileString, path, MAXPATHLEN);
3523 if (error)
3524 return errWrongType;
3525 } else {
3526 sc_GetUserConfigDirectory(path, PATH_MAX);
3527 sc_AppendToPath(path, MAXPATHLEN, "sclang_conf.yaml");
3530 gLibraryConfig->writeLibraryConfigYAML(path);
3531 return errNone;
3534 extern bool gPostInlineWarnings;
3535 static int prLanguageConfig_getPostInlineWarnings(struct VMGlobals * g, int numArgsPushed)
3537 PyrSlot *result = g->sp;
3538 SetBool(result, gPostInlineWarnings);
3539 return errNone;
3542 static int prLanguageConfig_setPostInlineWarnings(struct VMGlobals * g, int numArgsPushed)
3544 PyrSlot *arg = g->sp;
3546 if (IsTrue(arg))
3547 gPostInlineWarnings = true;
3548 else if (IsFalse(arg))
3549 gPostInlineWarnings = false;
3550 else
3551 return errWrongType;
3553 return errNone;
3557 #define PRIMGROWSIZE 480
3558 PrimitiveTable gPrimitiveTable;
3560 void initPrimitiveTable()
3562 int i;
3563 gPrimitiveTable.maxsize = PRIMGROWSIZE;
3564 gPrimitiveTable.size = 0;
3565 // pyrmalloc:
3566 // lifetime: runtime. primitives are reloaded when library is compiled.
3567 gPrimitiveTable.table = (PrimitiveDef*)pyr_pool_runtime->Alloc(gPrimitiveTable.maxsize * sizeof(PrimitiveDef));
3568 MEMFAIL(gPrimitiveTable.table);
3569 for (i=0; i<gPrimitiveTable.maxsize; ++i) {
3570 gPrimitiveTable.table[i].func = undefinedPrimitive;
3571 gPrimitiveTable.table[i].name = s_none;
3572 gPrimitiveTable.table[i].base = 0;
3573 gPrimitiveTable.table[i].numArgs = 0;
3574 gPrimitiveTable.table[i].varArgs = 0;
3575 gPrimitiveTable.table[i].keyArgs = 0;
3579 void growPrimitiveTable(int newsize)
3581 PrimitiveDef *oldtable;
3582 int i, oldsize;
3583 //postfl("growPrimitiveTable %d %d\n", oldsize, newsize);
3584 oldtable = gPrimitiveTable.table;
3585 oldsize = gPrimitiveTable.maxsize;
3586 gPrimitiveTable.maxsize = newsize;
3587 // pyrmalloc:
3588 // lifetime: runtime. primitives are reloaded when library is compiled.
3589 gPrimitiveTable.table = (PrimitiveDef*)pyr_pool_runtime->Alloc(gPrimitiveTable.maxsize * sizeof(PrimitiveDef));
3590 MEMFAIL(gPrimitiveTable.table);
3591 memcpy(gPrimitiveTable.table, oldtable, oldsize * sizeof(PrimitiveDef));
3592 for (i=oldsize; i<gPrimitiveTable.maxsize; ++i) {
3593 gPrimitiveTable.table[i].func = undefinedPrimitive;
3594 gPrimitiveTable.table[i].name = s_none;
3595 gPrimitiveTable.table[i].base = 0;
3596 gPrimitiveTable.table[i].numArgs = 0;
3597 gPrimitiveTable.table[i].varArgs = 0;
3598 gPrimitiveTable.table[i].keyArgs = 0;
3600 pyr_pool_runtime->Free(oldtable);
3603 int definePrimitive(int base, int index, const char *name, PrimitiveHandler handler,
3604 int numArgs, int varArgs)
3606 int tableIndex;
3607 PyrSymbol *sym;
3609 if (name[0] != '_') {
3610 error("*** Primitive Name must begin with an underscore ***\n");
3611 postfl("name: '%s' index: %d\n", name, index);
3612 return -1;
3614 tableIndex = base + index;
3615 if (tableIndex < 0) {
3616 error("*** Negative Primitive Index ***\n");
3617 postfl("name: '%s' index: %d\n", name, tableIndex);
3618 return -1;
3620 if (tableIndex >= gPrimitiveTable.maxsize) {
3621 growPrimitiveTable(tableIndex + PRIMGROWSIZE);
3623 if (gPrimitiveTable.table[tableIndex].func != undefinedPrimitive) {
3624 error("*** Duplicate Primitive Index ***\n");
3625 postfl("name: '%s' index: %d\n", name, tableIndex);
3626 return -1;
3628 sym = getsym(name);
3629 gPrimitiveTable.table[tableIndex].func = handler;
3630 gPrimitiveTable.table[tableIndex].name = sym;
3631 gPrimitiveTable.table[tableIndex].base = base;
3632 gPrimitiveTable.table[tableIndex].numArgs = numArgs;
3633 gPrimitiveTable.table[tableIndex].varArgs = varArgs;
3634 gPrimitiveTable.table[tableIndex].keyArgs = 0;
3635 if (tableIndex > gPrimitiveTable.size) gPrimitiveTable.size = tableIndex;
3636 sym->u.index = tableIndex;
3637 return tableIndex;
3640 int definePrimitiveWithKeys(int base, int index, const char *name,
3641 PrimitiveHandler handler, PrimitiveWithKeysHandler keyhandler,
3642 int numArgs, int varArgs)
3644 int tableIndex;
3645 PyrSymbol *sym;
3647 if (name[0] != '_') {
3648 error("*** Primitive Name must begin with an underscore ***\n");
3649 postfl("name: '%s' index: %d\n", name, index);
3650 return -1;
3652 tableIndex = base + index;
3653 if (tableIndex < 0) {
3654 error("*** Negative Primitive Index ***\n");
3655 postfl("name: '%s' index: %d\n", name, tableIndex);
3656 return -1;
3658 if (tableIndex+1 >= gPrimitiveTable.maxsize) {
3659 growPrimitiveTable(tableIndex + PRIMGROWSIZE);
3661 if (gPrimitiveTable.table[tableIndex].func != undefinedPrimitive) {
3662 error("*** Duplicate Primitive Index ***\n");
3663 postfl("name: '%s' index: %d\n", name, tableIndex);
3664 return -1;
3666 sym = getsym(name);
3667 gPrimitiveTable.table[tableIndex].func = handler;
3668 gPrimitiveTable.table[tableIndex].name = sym;
3669 gPrimitiveTable.table[tableIndex].base = base;
3670 gPrimitiveTable.table[tableIndex].numArgs = numArgs;
3671 gPrimitiveTable.table[tableIndex].varArgs = varArgs;
3672 gPrimitiveTable.table[tableIndex].keyArgs = 1;
3673 sym->u.index = tableIndex;
3675 tableIndex++;
3676 gPrimitiveTable.table[tableIndex].func = (PrimitiveHandler)keyhandler;
3677 gPrimitiveTable.table[tableIndex].name = sym;
3678 gPrimitiveTable.table[tableIndex].base = base;
3679 gPrimitiveTable.table[tableIndex].numArgs = numArgs;
3680 gPrimitiveTable.table[tableIndex].varArgs = varArgs;
3681 gPrimitiveTable.table[tableIndex].keyArgs = 1;
3682 if (tableIndex > gPrimitiveTable.size) gPrimitiveTable.size = tableIndex;
3683 return tableIndex;
3686 int nextPrimitiveIndex()
3688 return gPrimitiveTable.size + 1;
3692 void doPrimitive(VMGlobals* g, PyrMethod* meth, int numArgsPushed)
3696 #ifdef GC_SANITYCHECK
3697 g->gc->SanityCheck();
3698 #endif
3700 //post("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3702 PyrMethodRaw *methraw = METHRAW(meth);
3703 int primIndex = methraw->specialIndex;
3705 PrimitiveDef *def = gPrimitiveTable.table + primIndex;
3706 int numArgsNeeded = def->numArgs;
3707 int diff = numArgsNeeded - numArgsPushed;
3709 if (diff != 0) { // incorrect num of args
3710 if (diff > 0) { // not enough args
3711 PyrSlot* pslot = g->sp;
3712 PyrSlot* qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
3713 for (int m=0; m<diff; ++m) slotCopy(++pslot, ++qslot);
3715 g->sp += diff;
3716 } else if (def->varArgs) { // has var args
3717 numArgsNeeded = numArgsPushed;
3718 } else {
3719 g->sp += diff; // remove excess args
3722 g->numpop = numArgsNeeded - 1;
3723 g->primitiveIndex = primIndex - def->base;
3724 g->primitiveMethod = meth;
3725 g->args = g->sp - numArgsNeeded;
3726 int err;
3727 try {
3728 #ifdef GC_SANITYCHECK
3729 g->gc->SanityCheck();
3730 #endif
3731 err = (*def->func)(g, numArgsNeeded);
3732 #ifdef GC_SANITYCHECK
3733 g->gc->SanityCheck();
3734 #endif
3735 } catch (std::exception& ex) {
3736 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3737 error(ex.what());
3738 err = errException;
3739 } catch (...) {
3740 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3741 err = errException;
3743 if (err <= errNone) g->sp -= g->numpop;
3744 else {
3745 //post("primitive failed %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3746 SetInt(&g->thread->primitiveIndex, methraw->specialIndex);
3747 SetInt(&g->thread->primitiveError, err);
3748 executeMethod(g, meth, numArgsNeeded);
3750 #ifdef GC_SANITYCHECK
3751 g->gc->SanityCheck();
3752 #endif
3755 void doPrimitiveWithKeys(VMGlobals* g, PyrMethod* meth, int allArgsPushed, int numKeyArgsPushed)
3757 int i, j, m, diff, err;
3758 PyrSlot *pslot, *qslot;
3759 int numArgsNeeded, numArgsPushed;
3761 #ifdef GC_SANITYCHECK
3762 g->gc->SanityCheck();
3763 #endif
3764 //post("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3765 //printf("doPrimitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3767 PyrMethodRaw *methraw = METHRAW(meth);
3768 int primIndex = methraw->specialIndex;
3769 PrimitiveDef *def = gPrimitiveTable.table + primIndex;
3770 g->primitiveIndex = primIndex - def->base;
3771 g->primitiveMethod = meth;
3773 if (def->keyArgs && numKeyArgsPushed) {
3774 g->numpop = allArgsPushed - 1;
3775 try {
3776 err = ((PrimitiveWithKeysHandler)def[1].func)(g, allArgsPushed, numKeyArgsPushed);
3777 } catch (std::exception& ex) {
3778 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3779 error(ex.what());
3780 err = errException;
3781 } catch (...) {
3782 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3783 err = errException;
3785 if (err <= errNone) g->sp -= g->numpop;
3786 else {
3787 //post("primerr %d\n", err);
3788 SetInt(&g->thread->primitiveIndex, methraw->specialIndex);
3789 SetInt(&g->thread->primitiveError, err);
3790 executeMethodWithKeys(g, meth, allArgsPushed, numKeyArgsPushed);
3792 } else {
3793 numArgsNeeded = def->numArgs;
3794 numArgsPushed = allArgsPushed - (numKeyArgsPushed << 1);
3796 if (numKeyArgsPushed) {
3797 // evacuate keyword args to separate area
3798 pslot = keywordstack + (numKeyArgsPushed<<1);
3799 qslot = g->sp + 1;
3800 for (m=0; m<numKeyArgsPushed; ++m) {
3801 slotCopy(--pslot, --qslot);
3802 slotCopy(--pslot, --qslot);
3806 diff = numArgsNeeded - numArgsPushed;
3807 if (diff != 0) { // incorrect num of args
3808 if (diff > 0) { // not enough args
3809 g->sp += numArgsNeeded - allArgsPushed; // remove excess args
3810 pslot = g->sp - diff;
3811 qslot = slotRawObject(&meth->prototypeFrame)->slots + numArgsPushed - 1;
3812 for (m=0; m<diff; ++m) slotCopy(++pslot, ++qslot);
3813 } else if (def->varArgs) { // has var args
3814 numArgsNeeded = numArgsPushed;
3815 g->sp += numArgsNeeded - allArgsPushed; // remove excess args
3816 } else {
3817 g->sp += numArgsNeeded - allArgsPushed; // remove excess args
3821 // do keyword lookup:
3822 if (numKeyArgsPushed && methraw->posargs) {
3823 PyrSymbol **name0, **name;
3824 PyrSlot *key, *vars;
3825 name0 = slotRawSymbolArray(&meth->argNames)->symbols + 1;
3826 key = keywordstack;
3827 vars = g->sp - numArgsNeeded + 1;
3828 for (i=0; i<numKeyArgsPushed; ++i, key+=2) {
3829 name = name0;
3830 for (j=1; j<methraw->posargs; ++j, ++name) {
3831 if (*name == slotRawSymbol(key)) {
3832 slotCopy(&vars[j],&key[1]);
3833 goto found;
3836 if (gKeywordError) {
3837 post("WARNING: keyword arg '%s' not found in call to %s:%s\n",
3838 slotRawSymbol(key)->name, slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3840 found: ;
3843 g->numpop = numArgsNeeded - 1;
3844 try {
3845 err = (*def->func)(g, numArgsNeeded);
3846 } catch (std::exception& ex) {
3847 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3848 error(ex.what());
3849 err = errException;
3850 } catch (...) {
3851 post("caught exception in primitive %s:%s\n", slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name);
3852 err = errException;
3854 if (err <= errNone) g->sp -= g->numpop;
3855 else {
3856 //post("primerr %d\n", err);
3857 SetInt(&g->thread->primitiveIndex, methraw->specialIndex);
3858 SetInt(&g->thread->primitiveError, err);
3859 executeMethod(g, meth, numArgsNeeded);
3862 #ifdef GC_SANITYCHECK
3863 g->gc->SanityCheck();
3864 #endif
3867 void initPrimitives()
3869 int base, index;
3871 initPrimitiveTable();
3873 // unary operators
3874 base = nextPrimitiveIndex();
3875 definePrimitive(base, opNeg, "_Neg", doSpecialUnaryArithMsg, 1, 0);
3876 definePrimitive(base, opBitNot, "_BitNot", doSpecialUnaryArithMsg, 1, 0);
3877 definePrimitive(base, opAbs, "_Abs", doSpecialUnaryArithMsg, 1, 0);
3878 definePrimitive(base, opAsFloat, "_AsFloat", doSpecialUnaryArithMsg, 1, 0);
3879 definePrimitive(base, opAsInt, "_AsInt", doSpecialUnaryArithMsg, 1, 0);
3880 definePrimitive(base, opCeil, "_Ceil", doSpecialUnaryArithMsg, 1, 0); // 5
3881 definePrimitive(base, opFloor, "_Floor", doSpecialUnaryArithMsg, 1, 0);
3882 definePrimitive(base, opFrac, "_Frac", doSpecialUnaryArithMsg, 1, 0);
3883 definePrimitive(base, opSign, "_Sign", doSpecialUnaryArithMsg, 1, 0);
3884 definePrimitive(base, opSquared, "_Squared", doSpecialUnaryArithMsg, 1, 0);
3885 definePrimitive(base, opCubed, "_Cubed", doSpecialUnaryArithMsg, 1, 0); //10
3886 definePrimitive(base, opSqrt, "_Sqrt", doSpecialUnaryArithMsg, 1, 0);
3887 definePrimitive(base, opExp, "_Exp", doSpecialUnaryArithMsg, 1, 0);
3888 definePrimitive(base, opRecip, "_Recip", doSpecialUnaryArithMsg, 1, 0);
3889 definePrimitive(base, opMIDICPS, "_MIDICPS", doSpecialUnaryArithMsg, 1, 0);
3890 definePrimitive(base, opCPSMIDI, "_CPSMIDI", doSpecialUnaryArithMsg, 1, 0); //15
3892 definePrimitive(base, opMIDIRatio, "_MIDIRatio", doSpecialUnaryArithMsg, 1, 0);
3893 definePrimitive(base, opRatioMIDI, "_RatioMIDI", doSpecialUnaryArithMsg, 1, 0);
3894 definePrimitive(base, opDbAmp, "_DbAmp", doSpecialUnaryArithMsg, 1, 0);
3895 definePrimitive(base, opAmpDb, "_AmpDb", doSpecialUnaryArithMsg, 1, 0);
3896 definePrimitive(base, opOctCPS, "_OctCPS", doSpecialUnaryArithMsg, 1, 0);
3897 definePrimitive(base, opCPSOct, "_CPSOct", doSpecialUnaryArithMsg, 1, 0);
3898 definePrimitive(base, opLog, "_Log", doSpecialUnaryArithMsg, 1, 0);
3899 definePrimitive(base, opLog2, "_Log2", doSpecialUnaryArithMsg, 1, 0);
3900 definePrimitive(base, opLog10, "_Log10", doSpecialUnaryArithMsg, 1, 0);
3901 definePrimitive(base, opSin, "_Sin", doSpecialUnaryArithMsg, 1, 0);
3902 definePrimitive(base, opCos, "_Cos", doSpecialUnaryArithMsg, 1, 0);
3903 definePrimitive(base, opTan, "_Tan", doSpecialUnaryArithMsg, 1, 0);
3904 definePrimitive(base, opArcSin, "_ArcSin", doSpecialUnaryArithMsg, 1, 0);
3905 definePrimitive(base, opArcCos, "_ArcCos", doSpecialUnaryArithMsg, 1, 0);
3906 definePrimitive(base, opArcTan, "_ArcTan", doSpecialUnaryArithMsg, 1, 0);
3907 definePrimitive(base, opSinH, "_SinH", doSpecialUnaryArithMsg, 1, 0);
3908 definePrimitive(base, opCosH, "_CosH", doSpecialUnaryArithMsg, 1, 0);
3909 definePrimitive(base, opTanH, "_TanH", doSpecialUnaryArithMsg, 1, 0);
3910 definePrimitive(base, opRand, "_Rand", doSpecialUnaryArithMsg, 1, 0);
3911 definePrimitive(base, opRand2, "_Rand2", doSpecialUnaryArithMsg, 1, 0);
3912 definePrimitive(base, opLinRand, "_LinRand", doSpecialUnaryArithMsg, 1, 0);
3913 definePrimitive(base, opBiLinRand, "_BiLinRand", doSpecialUnaryArithMsg, 1, 0);
3915 definePrimitive(base, opSum3Rand, "_Sum3Rand", doSpecialUnaryArithMsg, 1, 0);
3916 // definePrimitive(base, opExpRand, "_ExpRand", doSpecialUnaryArithMsg, 1, 0);
3917 // definePrimitive(base, opBiExpRand, "_BiExpRand", doSpecialUnaryArithMsg, 1, 0);
3918 // definePrimitive(base, opGammaRand, "_GammaRand", doSpecialUnaryArithMsg, 1, 0);
3919 // definePrimitive(base, opGaussRand, "_GaussRand", doSpecialUnaryArithMsg, 1, 0);
3920 // definePrimitive(base, opPoiRand, "_PoiRand", doSpecialUnaryArithMsg, 1, 0);
3922 definePrimitive(base, opDistort, "_Distort", doSpecialUnaryArithMsg, 1, 0);
3923 definePrimitive(base, opSoftClip, "_SoftClip", doSpecialUnaryArithMsg, 1, 0);
3924 definePrimitive(base, opCoin, "_Coin", doSpecialUnaryArithMsg, 1, 0);
3926 definePrimitive(base, opRectWindow, "_RectWindow", doSpecialUnaryArithMsg, 1, 0);
3927 definePrimitive(base, opHanWindow, "_HanWindow", doSpecialUnaryArithMsg, 1, 0);
3928 definePrimitive(base, opWelchWindow, "_WelchWindow", doSpecialUnaryArithMsg, 1, 0);
3929 definePrimitive(base, opTriWindow, "_TriWindow", doSpecialUnaryArithMsg, 1, 0);
3931 definePrimitive(base, opSCurve, "_SCurve", doSpecialUnaryArithMsg, 1, 0);
3932 definePrimitive(base, opRamp, "_Ramp", doSpecialUnaryArithMsg, 1, 0);
3934 definePrimitive(base, opDigitValue, "_DigitValue", doSpecialUnaryArithMsg, 1, 0);
3937 // binary operators
3938 base = nextPrimitiveIndex();
3939 definePrimitive(base, opAdd, "_Add", prAddNum, 2, 0);
3940 definePrimitive(base, opSub, "_Sub", prSubNum, 2, 0);
3941 definePrimitive(base, opMul, "_Mul", prMulNum, 2, 0);
3943 definePrimitive(base, opIDiv, "_IDiv", prSpecialBinaryArithMsg, 3, 0);
3944 definePrimitive(base, opFDiv, "_FDiv", prSpecialBinaryArithMsg, 3, 0);
3945 definePrimitive(base, opMod, "_Mod", prSpecialBinaryArithMsg, 3, 0);
3946 definePrimitive(base, opEQ, "_EQ", prSpecialBinaryArithMsg, 3, 0);
3947 definePrimitive(base, opNE, "_NE", prSpecialBinaryArithMsg, 3, 0);
3948 definePrimitive(base, opLT, "_LT", prSpecialBinaryArithMsg, 3, 0);
3949 definePrimitive(base, opGT, "_GT", prSpecialBinaryArithMsg, 3, 0);
3950 definePrimitive(base, opLE, "_LE", prSpecialBinaryArithMsg, 3, 0);
3951 definePrimitive(base, opGE, "_GE", prSpecialBinaryArithMsg, 3, 0);
3952 //definePrimitive(base, opIdentical, "_Identical", prSpecialBinaryArithMsg, 3, 0);
3953 //definePrimitive(base, opNotIdentical, "_NotIdentical", prSpecialBinaryArithMsg, 3, 0);
3955 definePrimitive(base, opMin, "_Min", prSpecialBinaryArithMsg, 3, 0);
3956 definePrimitive(base, opMax, "_Max", prSpecialBinaryArithMsg, 3, 0);
3957 definePrimitive(base, opBitAnd, "_BitAnd", prSpecialBinaryArithMsg, 3, 0);
3958 definePrimitive(base, opBitOr, "_BitOr", prSpecialBinaryArithMsg, 3, 0);
3959 definePrimitive(base, opBitXor, "_BitXor", prSpecialBinaryArithMsg, 3, 0);
3960 definePrimitive(base, opLCM, "_LCM", prSpecialBinaryArithMsg, 3, 0);
3961 definePrimitive(base, opGCD, "_GCD", prSpecialBinaryArithMsg, 3, 0);
3962 definePrimitive(base, opRound, "_Round", prSpecialBinaryArithMsg, 3, 0);
3963 definePrimitive(base, opRoundUp, "_RoundUp", prSpecialBinaryArithMsg, 3, 0);
3964 definePrimitive(base, opTrunc, "_Trunc", prSpecialBinaryArithMsg, 3, 0);
3965 definePrimitive(base, opAtan2, "_Atan2", prSpecialBinaryArithMsg, 3, 0);
3966 definePrimitive(base, opHypot, "_Hypot", prSpecialBinaryArithMsg, 3, 0);
3967 definePrimitive(base, opHypotx, "_HypotApx", prSpecialBinaryArithMsg, 3, 0);
3968 definePrimitive(base, opPow, "_Pow", prSpecialBinaryArithMsg, 3, 0);
3969 definePrimitive(base, opShiftLeft, "_ShiftLeft", prSpecialBinaryArithMsg, 3, 0);
3970 definePrimitive(base, opShiftRight, "_ShiftRight", prSpecialBinaryArithMsg, 3, 0);
3971 definePrimitive(base, opUnsignedShift, "_UnsignedShift", prSpecialBinaryArithMsg, 3, 0);
3972 definePrimitive(base, opFill, "_Fill", prSpecialBinaryArithMsg, 3, 0);
3973 definePrimitive(base, opRing1, "_Ring1", prSpecialBinaryArithMsg, 3, 0); // a * (b + 1) == a * b + a
3974 definePrimitive(base, opRing2, "_Ring2", prSpecialBinaryArithMsg, 3, 0); // a * b + a + b
3975 definePrimitive(base, opRing3, "_Ring3", prSpecialBinaryArithMsg, 3, 0); // a*a*b
3976 definePrimitive(base, opRing4, "_Ring4", prSpecialBinaryArithMsg, 3, 0); // a*a*b - a*b*b
3977 definePrimitive(base, opDifSqr, "_DifSqr", prSpecialBinaryArithMsg, 3, 0); // a*a - b*b
3978 definePrimitive(base, opSumSqr, "_SumSqr", prSpecialBinaryArithMsg, 3, 0); // a*a + b*b
3979 definePrimitive(base, opSqrSum, "_SqrSum", prSpecialBinaryArithMsg, 3, 0); // (a + b)^2
3980 definePrimitive(base, opSqrDif, "_SqrDif", prSpecialBinaryArithMsg, 3, 0); // (a - b)^2
3981 definePrimitive(base, opAbsDif, "_AbsDif", prSpecialBinaryArithMsg, 3, 0); // abs(a - b)
3982 definePrimitive(base, opThresh, "_Thresh", prSpecialBinaryArithMsg, 3, 0); // a * max(0,b)
3983 definePrimitive(base, opAMClip, "_AMClip", prSpecialBinaryArithMsg, 3, 0); // a * max(0,b)
3984 definePrimitive(base, opScaleNeg, "_ScaleNeg", prSpecialBinaryArithMsg, 3, 0); // a < 0 ? a*b : a
3985 definePrimitive(base, opClip2, "_Clip2", prSpecialBinaryArithMsg, 3, 0);
3986 definePrimitive(base, opFold2, "_Fold2", prSpecialBinaryArithMsg, 3, 0);
3987 definePrimitive(base, opWrap2, "_Wrap2", prSpecialBinaryArithMsg, 3, 0);
3988 definePrimitive(base, opExcess, "_Excess", prSpecialBinaryArithMsg, 3, 0);
3989 definePrimitive(base, opFirstArg, "_FirstArg", prSpecialBinaryArithMsg, 3, 0);
3990 definePrimitive(base, opRandRange, "_RandRange", prSpecialBinaryArithMsg, 3, 0);
3991 definePrimitive(base, opExpRandRange, "_ExpRandRange", prSpecialBinaryArithMsg, 3, 0);
3993 // general primitives
3994 base = nextPrimitiveIndex();
3995 index = 0;
3996 definePrimitive(base, index++, "_Halt", haltInterpreter, 1, 0);
3997 definePrimitive(base, index++, "_InstVarAt", instVarAt, 2, 0);
3998 definePrimitive(base, index++, "_InstVarPut", instVarPut, 3, 0);
3999 definePrimitive(base, index++, "_InstVarSize", instVarSize, 1, 0);
4000 definePrimitive(base, index++, "_ObjectHash", objectHash, 1, 0);
4001 definePrimitive(base, index++, "_ObjectClass", objectClass, 1, 0);
4002 definePrimitive(base, index++, "_BasicNew", basicNew, 2, 0);
4003 definePrimitive(base, index++, "_BasicNewClear", basicNewClear, 2, 0);
4004 definePrimitive(base, index++, "_BasicNewCopyArgsToInstVars", basicNewCopyArgsToInstanceVars, 1, 1);
4005 //definePrimitive(base, index++, "_BasicNewCopyArgsByName", basicNewCopyArgsByName, 1, 1);
4007 definePrimitiveWithKeys(base, index, "_FunctionValue", blockValue, blockValueWithKeys, 1, 1);
4008 index+=2;
4009 definePrimitiveWithKeys(base, index, "_FunctionValueEnvir", blockValueEnvir, blockValueEnvirWithKeys, 1, 1);
4010 index+=2;
4012 definePrimitive(base, index++, "_FunctionValueArray", blockValueArray, 1, 1);
4013 definePrimitive(base, index++, "_FunctionValueArrayEnvir", blockValueArrayEnvir, 1, 1);
4014 definePrimitive(base, index++, "_FunctionDefAsFunction", prFunctionDefAsFunction, 1, 0);
4015 definePrimitive(base, index++, "_FunctionDefDumpContexts", prFunctionDefDumpContexts, 1, 0);
4016 definePrimitive(base, index++, "_FunctionDefIsClosed", prFunctionDefIsClosed, 1, 0);
4017 definePrimitive(base, index++, "_FunctionDefIsWithinClosed", prFunctionDefIsWithinClosed, 1, 0);
4019 definePrimitive(base, index++, "_ObjectIsKindOf", objectIsKindOf, 2, 0);
4020 definePrimitive(base, index++, "_ObjectIsMemberOf", objectIsMemberOf, 2, 0);
4021 definePrimitive(base, index++, "_ObjectDump", objectDump, 1, 0);
4022 definePrimitive(base, index++, "_TotalFree", prTotalFree, 1, 0);
4023 definePrimitive(base, index++, "_LargestFreeBlock", prLargestFreeBlock, 1, 0);
4025 definePrimitive(base, index++, "_GCInfo", dumpGCinfo, 1, 0);
4026 definePrimitive(base, index++, "_GCDumpGrey", dumpGCdumpGrey, 1, 0);
4027 definePrimitive(base, index++, "_GCDumpSet", dumpGCdumpSet, 2, 0);
4028 definePrimitive(base, index++, "_GCSanity", prGCSanity, 1, 0);
4029 #if GCDEBUG
4030 definePrimitive(base, index++, "_TraceAllPathsTo", prTraceAllPathsTo, 1, 0);
4031 definePrimitive(base, index++, "_TraceAnyPathsTo", prTraceAnyPathsTo, 1, 0);
4032 definePrimitive(base, index++, "_TraceAnyPathToAllInstancesOf", prTraceAnyPathToAllInstancesOf, 1, 0);
4033 #endif
4035 definePrimitive(base, index++, "_Identical", objectIdentical, 2, 0);
4036 definePrimitive(base, index++, "_NotIdentical", objectNotIdentical, 2, 0);
4037 definePrimitiveWithKeys(base, index, "_ObjectPerform", objectPerform, objectPerformWithKeys, 2, 1);
4038 index+=2;
4039 definePrimitive(base, index++, "_ObjectPerformList", objectPerformList, 2, 1);
4040 definePrimitiveWithKeys(base, index, "_SuperPerform", objectSuperPerform, objectSuperPerformWithKeys, 2, 1);
4041 index+=2;
4042 definePrimitive(base, index++, "_SuperPerformList", objectSuperPerformList, 2, 1);
4043 definePrimitive(base, index++, "_ObjectPerformMsg", objectPerformSelList, 2, 0);
4044 //definePrimitive(base, index++, "_ArrayPerformMsg", arrayPerformMsg, 1, 1);
4045 definePrimitive(base, index++, "_ObjectString", prObjectString, 1, 0);
4046 definePrimitive(base, index++, "_Float_AsStringPrec", prFloat_AsStringPrec, 2, 0);
4047 definePrimitive(base, index++, "_ObjectCompileString", prAsCompileString, 1, 0);
4048 definePrimitive(base, index++, "_ClassString", prClassString, 1, 0);
4049 definePrimitive(base, index++, "_PostString", prPostString, 1, 0);
4050 definePrimitive(base, index++, "_PostLine", prPostLine, 1, 0);
4051 definePrimitive(base, index++, "_HostDebugger", prDebugger, 1, 0);
4052 definePrimitive(base, index++, "_Trace", prTraceOn, 1, 0);
4053 definePrimitive(base, index++, "_CanCallOS", prCanCallOS, 1, 0);
4054 definePrimitive(base, index++, "_KeywordError", prKeywordError, 1, 0);
4055 definePrimitive(base, index++, "_GetTailCallOptimize", prGetTailCallOptimize, 1, 0);
4056 definePrimitive(base, index++, "_SetTailCallOptimize", prSetTailCallOptimize, 2, 0);
4059 definePrimitive(base, index++, "_PrimitiveError", prPrimitiveError, 1, 0);
4060 definePrimitive(base, index++, "_PrimitiveErrorString", prPrimitiveErrorString, 1, 0);
4061 definePrimitive(base, index++, "_DumpStack", prDumpStack, 1, 0);
4062 definePrimitive(base, index++, "_DumpDetailedBackTrace", prDumpDetailedBackTrace, 1, 0);
4063 definePrimitive(base, index++, "_StackDepth", prStackDepth, 1, 0);
4064 definePrimitive(base, index++, "_PrimName", prPrimName, 1, 0);
4065 definePrimitive(base, index++, "_ObjectShallowCopy", prObjectShallowCopy, 1, 0);
4066 definePrimitive(base, index++, "_ObjectCopyImmutable", prObjectCopyImmutable, 1, 0);
4067 definePrimitive(base, index++, "_ObjectCopyRange", prObjectCopyRange, 3, 0);
4068 definePrimitive(base, index++, "_ObjectCopySeries", prObjectCopySeries, 4, 0);
4069 definePrimitive(base, index++, "_ObjectPointsTo", prObjectPointsTo, 2, 0);
4070 definePrimitive(base, index++, "_ObjectRespondsTo", prObjectRespondsTo, 2, 0);
4071 definePrimitive(base, index++, "_ObjectIsMutable", prObjectIsMutable, 1, 0);
4072 definePrimitive(base, index++, "_ObjectIsPermanent", prObjectIsPermanent, 1, 0);
4073 definePrimitive(base, index++, "_ObjectDeepFreeze", prDeepFreeze, 1, 0);
4074 definePrimitive(base, index++, "_ObjectDeepCopy", prDeepCopy, 1, 0);
4076 #if !SCPLAYER
4077 definePrimitive(base, index++, "_CompileExpression", prCompileString, 2, 0);
4078 #endif
4079 definePrimitive(base, index++, "_GetBackTrace", prGetBackTrace, 1, 0);
4080 definePrimitive(base, index++, "_DumpBackTrace", prDumpBackTrace, 1, 0);
4081 definePrimitive(base, index++, "_DumpByteCodes", prDumpByteCodes, 1, 0);
4083 definePrimitive(base, index++, "_AllClasses", prAllClasses, 1, 0);
4084 definePrimitive(base, index++, "_DumpClassSubtree", prPostClassTree, 1, 0);
4086 // definePrimitive(base, index++, "_TabletTracking", prTabletTracking, 1, 0);
4088 definePrimitive(base, index++, "_FunDef_NumArgs", prFunDef_NumArgs, 1, 0);
4089 definePrimitive(base, index++, "_FunDef_NumVars", prFunDef_NumVars, 1, 0);
4090 definePrimitive(base, index++, "_FunDef_VarArgs", prFunDef_VarArgs, 1, 0);
4092 definePrimitive(base, index++, "_Thread_Init", prThreadInit, 3, 0);
4093 definePrimitive(base, index++, "_Thread_RandSeed", prThreadRandSeed, 2, 0);
4094 definePrimitive(base, index++, "_Thread_GetRandData", prThreadGetRandData, 1, 0);
4095 definePrimitive(base, index++, "_Thread_SetRandData", prThreadSetRandData, 2, 0);
4096 // definePrimitive(base, index++, "_ThreadRun", prThreadRun, 2, 0);
4097 // definePrimitive(base, index++, "_RunNextThread", prRunNextThread, 1, 0);
4098 definePrimitive(base, index++, "_RoutineYield", prRoutineYield, 1, 0);
4099 definePrimitive(base, index++, "_RoutineAlwaysYield", prRoutineAlwaysYield, 1, 0);
4100 definePrimitive(base, index++, "_RoutineResume", prRoutineResume, 2, 0);
4101 definePrimitive(base, index++, "_RoutineReset", prRoutineReset, 1, 0);
4102 definePrimitive(base, index++, "_RoutineYieldAndReset", prRoutineYieldAndReset, 2, 0);
4103 definePrimitive(base, index++, "_RoutineStop", prRoutineStop, 1, 0);
4105 // definePrimitive(base, index++, "_IsDemo", prIsDemo, 1, 0);
4106 definePrimitive(base, index++, "_Blork", prBlork, 1, 0);
4107 definePrimitive(base, index++, "_UGenCodeString", prUGenCodeString, 5, 0);
4108 definePrimitive(base, index++, "_MainOverwriteMsg", prOverwriteMsg, 1, 0);
4110 definePrimitive(base, index++, "_AppClock_SchedNotify", prAppClockSchedNotify, 1, 0);
4111 definePrimitive(base, index++, "_LanguageConfig_getIncludePaths", prLanguageConfig_getIncludePaths, 1, 0);
4112 definePrimitive(base, index++, "_LanguageConfig_getExcludePaths", prLanguageConfig_getExcludePaths, 1, 0);
4113 definePrimitive(base, index++, "_LanguageConfig_addIncludePath", prLanguageConfig_addIncludePath, 2, 0);
4114 definePrimitive(base, index++, "_LanguageConfig_addExcludePath", prLanguageConfig_addExcludePath, 2, 0);
4115 definePrimitive(base, index++, "_LanguageConfig_removeIncludePath", prLanguageConfig_removeIncludePath, 2, 0);
4116 definePrimitive(base, index++, "_LanguageConfig_removeExcludePath", prLanguageConfig_removeExcludePath, 2, 0);
4117 definePrimitive(base, index++, "_LanguageConfig_writeConfigFile", prLanguageConfig_writeConfigFile, 2, 0);
4118 definePrimitive(base, index++, "_LanguageConfig_getPostInlineWarnings", prLanguageConfig_getPostInlineWarnings, 1, 0);
4119 definePrimitive(base, index++, "_LanguageConfig_setPostInlineWarnings", prLanguageConfig_setPostInlineWarnings, 2, 0);
4121 //void initOscilPrimitives();
4122 //void initControllerPrimitives();
4124 //initOscilPrimitives();
4125 //initControllerPrimitives();
4126 initMathPrimitives();
4127 initSignalPrimitives();
4128 initArrayPrimitives();
4130 void initSymbolPrimitives();
4131 initSymbolPrimitives();
4133 void initArchiverPrimitives();
4134 initArchiverPrimitives();
4136 void initArrayPrimitives();
4137 initArrayPrimitives();
4139 void initBitPrimitives();
4140 initBitPrimitives();
4142 void initCharPrimitives();
4143 initCharPrimitives();
4145 void initFilePrimitives();
4146 initFilePrimitives();
4148 void initPlatformPrimitives();
4149 initPlatformPrimitives();
4151 void initStringPrimitives();
4152 initStringPrimitives();
4154 void initListPrimitives();
4155 initListPrimitives();
4158 void initUnixPrimitives();
4159 initUnixPrimitives();
4161 void init_OSC_primitives();
4162 init_OSC_primitives();
4164 /* these probably should be moved out of the Lang code
4165 into an App init primitives section */
4166 void initGUIPrimitives();
4167 initGUIPrimitives();
4169 void initSCViewPrimitives();
4170 initSCViewPrimitives();
4172 void initSchedPrimitives();
4173 initSchedPrimitives();
4175 #if defined(__APPLE__) || defined(HAVE_ALSA) || defined(HAVE_PORTMIDI)
4176 void initMIDIPrimitives();
4177 initMIDIPrimitives();
4178 #endif
4180 #if !defined(SC_WIN32) && !defined(SC_IPHONE)
4181 void initHIDPrimitives();
4182 initHIDPrimitives();
4184 void initSpeechPrimitives();
4185 initSpeechPrimitives();
4187 void initCocoaFilePrimitives();
4188 initCocoaFilePrimitives();
4190 void initCocoaBridgePrimitives();
4191 initCocoaBridgePrimitives();
4193 void initSerialPrimitives();
4194 initSerialPrimitives();
4196 void initWiiPrimitives();
4197 initWiiPrimitives();
4199 #endif
4200 #ifdef SC_DARWIN
4201 void initCoreAudioPrimitives();
4202 initCoreAudioPrimitives();
4203 #endif
4205 // CR ADDED
4206 void initRendezvousPrimitives();
4207 initRendezvousPrimitives();
4209 #ifdef SCOGL_COMPILE
4210 void initOpenGLPrimitives();
4211 initOpenGLPrimitives();
4212 #endif
4214 #ifdef SC_QT
4215 QtCollider::initPrimitives();
4216 #endif
4218 #ifdef SC_IDE
4219 void initScIDEPrimitives();
4220 initScIDEPrimitives();
4221 #endif
4223 initSCDocPrimitives();
4225 s_recvmsg = getsym("receiveMsg");
4226 post("\tNumPrimitives = %d\n", nextPrimitiveIndex());
4231 void initThreads();
4232 void initThreads()
4234 s_prrunnextthread = getsym("prRunNextThread");
4235 s_prready = getsym("prReady");