1 /*
2     SuperCollider real time audio synthesis system
3     Copyright (c) 2002 James McCartney. All rights reserved.
4     http://www.audiosynth.com
5 
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.
10 
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.
15 
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
19 */
20 
21 #include "SCBase.h"
22 #include "PyrParseNode.h"
23 #include "PyrLexer.h"
24 #include "PyrKernel.h"
25 #include "PyrListPrim.h"
26 #include "PyrSymbolTable.h"
27 #include "Opcodes.h"
28 #include "PyrKernelProto.h"
29 #include "PyrObjectProto.h"
30 #include "GC.h"
31 #include <new>
32 #include <string>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include "InitAlloc.h"
37 #include "PredefinedSymbols.h"
38 #include "SimpleStack.h"
39 #include "PyrPrimitive.h"
40 #include "SC_Win32Utils.h"
41 #include "SC_LanguageConfig.hpp"
42 #include "SC_Codecvt.hpp"
43 
44 namespace bfs = boost::filesystem;
45 
46 AdvancingAllocPool gParseNodePool;
47 
48 PyrSymbol* gSpecialUnarySelectors[opNumUnarySelectors];
49 PyrSymbol* gSpecialBinarySelectors[opNumBinarySelectors];
50 PyrSymbol* gSpecialSelectors[opmNumSpecialSelectors];
51 PyrSymbol* gSpecialClasses[op_NumSpecialClasses];
52 PyrSlot gSpecialValues[svNumSpecialValues];
53 
54 PyrParseNode* gRootParseNode;
55 intptr_t gParserResult;
56 
57 int conjureConstantIndex(PyrParseNode* node, PyrBlock* func, PyrSlot* slot);
58 void compilePushConstant(PyrParseNode* node, PyrSlot* slot);
59 
60 PyrClass* gCurrentClass = nullptr;
61 PyrClass* gCurrentMetaClass = nullptr;
62 PyrClass* gCompilingClass = nullptr;
63 PyrMethod* gCompilingMethod = nullptr;
64 PyrBlock* gCompilingBlock = nullptr;
65 PyrBlock* gPartiallyAppliedFunction = nullptr;
66 
67 bool gIsTailCodeBranch = false;
68 bool gTailIsMethodReturn = false;
69 int gFunctionHighestExternalRef = 1;
70 bool gFunctionCantBeClosed = true;
71 #if TAILCALLOPTIMIZE
72 bool gGenerateTailCallByteCodes = true;
73 #else
74 bool gGenerateTailCallByteCodes = false;
75 #endif
76 
77 long gInliningLevel;
78 
79 int compileErrors = 0;
80 int numOverwrites = 0;
81 std::string overwriteMsg;
82 
83 extern bool compilingCmdLine;
84 extern int errLineOffset, errCharPosOffset;
85 
86 const char* nodename[] = { "ClassNode", "ClassExtNode", "MethodNode", "BlockNode", "SlotNode",
87 
88                            /* variable declarations */
89                            "VarListNode", "VarDefNode", "DynDictNode", "DynListNode", "LitListNode", "LitDictNode",
90 
91                            "StaticVarListNode", "InstVarListNode", "PoolVarListNode", "ArgListNode", "SlotDefNode",
92 
93                            /* selectors */
94                            "LiteralNode",
95 
96                            /* code */
97                            "PushLitNode", "PushNameNode", "PushKeyArgNode", "CallNode", "BinopCallNode", "DropNode",
98                            "AssignNode", "MultiAssignNode", "MultiAssignVarListNode", "SetterNode", "CurryArgNode",
99 
100                            "ReturnNode", "BlockReturnNode" };
101 
compileTail()102 void compileTail() {
103     if (gGenerateTailCallByteCodes && gIsTailCodeBranch) {
104         // if (gCompilingClass && gCompilingMethod) post("tail call %s:%s  ismethod %d\n",
105         //	slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name,
106         // gTailIsMethodReturn);
107         if (gTailIsMethodReturn)
108             compileByte(255);
109         else
110             compileByte(176);
111     }
112 }
113 
114 
115 PyrGC* compileGC();
compileGC()116 PyrGC* compileGC() { return gCompilingVMGlobals ? gCompilingVMGlobals->gc : nullptr; }
117 
initParser()118 void initParser() {
119     compileErrors = 0;
120     numOverwrites = 0;
121     overwriteMsg.clear();
122 }
123 
finiParser()124 void finiParser() {}
125 
initParseNodes()126 void initParseNodes() {}
127 
initParserPool()128 void initParserPool() {
129     // postfl("initPool gParseNodePool pyr_pool_compile\n");
130     gParseNodePool.Init(pyr_pool_compile, 32000, 32000, 2000);
131 }
132 
freeParserPool()133 void freeParserPool() {
134     // postfl("freePool gParseNodePool pyr_pool_compile\n");
135     gParseNodePool.FreeAll();
136 }
137 
PyrParseNode(int inClassNo)138 PyrParseNode::PyrParseNode(int inClassNo) {
139     mClassno = inClassNo;
140     mNext = nullptr;
141     mTail = this;
142     mCharno = ::charno;
143     mLineno = ::lineno;
144     mParens = 0;
145 }
146 
compileNodeList(PyrParseNode * node,bool onTailBranch)147 void compileNodeList(PyrParseNode* node, bool onTailBranch) {
148     PyrSlot dummy;
149     // postfl("->compileNodeList\n");
150     for (; node; node = node->mNext) {
151         // postfl("-->compileNodeList %p\n", node);
152         COMPILENODE(node, &dummy, onTailBranch);
153         // postfl("<--compileNodeList %p\n", node);
154     }
155     // postfl("<-compileNodeList\n");
156 }
157 
nodePostErrorLine(PyrParseNode * node)158 void nodePostErrorLine(PyrParseNode* node) { postErrorLine(node->mLineno, linestarts[node->mLineno], node->mCharno); }
159 
newPyrPushNameNode(PyrSlotNode * slotNode)160 PyrPushNameNode* newPyrPushNameNode(PyrSlotNode* slotNode) {
161     slotNode->mClassno = pn_PushNameNode;
162     return (PyrPushNameNode*)slotNode;
163 }
164 
compilePushVar(PyrParseNode * node,PyrSymbol * varName)165 void compilePushVar(PyrParseNode* node, PyrSymbol* varName) {
166     int level, index, vindex, varType;
167     PyrBlock* tempfunc;
168     PyrClass* classobj;
169 
170     // postfl("compilePushVar\n");
171     classobj = gCompilingClass;
172     if (varName->name[0] >= 'A' && varName->name[0] <= 'Z') {
173         if (compilingCmdLine && varName->u.classobj == nullptr) {
174             error("Class not defined.\n");
175             nodePostErrorLine(node);
176             compileErrors++;
177         } else {
178             if (findSpecialClassName(varName, &index)) {
179                 compileOpcode(opExtended, opPushSpecialValue); // special op for pushing a class
180                 compileByte(index);
181             } else {
182                 PyrSlot slot;
183                 SetSymbol(&slot, varName);
184                 index = conjureLiteralSlotIndex(node, gCompilingBlock, &slot);
185                 compileOpcode(opExtended, opExtended); // special op for pushing a class
186                 compileByte(index);
187             }
188         }
189     } else if (varName == s_this || varName == s_super) {
190         gFunctionCantBeClosed = true;
191         compileOpcode(opPushSpecialValue, opsvSelf);
192     } else if (varName == s_true) {
193         compileOpcode(opPushSpecialValue, opsvTrue);
194     } else if (varName == s_false) {
195         compileOpcode(opPushSpecialValue, opsvFalse);
196     } else if (varName == s_nil) {
197         compileOpcode(opPushSpecialValue, opsvNil);
198     } else if (findVarName(gCompilingBlock, &classobj, varName, &varType, &level, &index, &tempfunc)) {
199         switch (varType) {
200         case varInst:
201             compileOpcode(opPushInstVar, index);
202             break;
203         case varClass: {
204             index += slotRawInt(&classobj->classVarIndex);
205             if (index < 4096) {
206                 compileByte((opPushClassVar << 4) | ((index >> 8) & 15));
207                 compileByte(index & 255);
208             } else {
209                 compileByte(opPushClassVar);
210                 compileByte((index >> 8) & 255);
211                 compileByte(index & 255);
212             }
213         } break;
214         case varConst: {
215             PyrSlot* slot = slotRawObject(&classobj->constValues)->slots + index;
216             compilePushConstant(node, slot);
217         } break;
218         case varTemp:
219             vindex = index;
220             if (level == 0) {
221                 compileOpcode(opPushTempZeroVar, vindex);
222             } else if (level < 8) {
223                 compileOpcode(opPushTempVar, level);
224                 compileByte(vindex);
225             } else {
226                 compileByte(opPushTempVar);
227                 compileByte(level);
228                 compileByte(vindex);
229             }
230             break;
231         case varPseudo:
232             compileOpcode(opExtended, opSpecialOpcode);
233             compileByte(index);
234             break;
235         }
236     } else {
237         error("Variable '%s' not defined.\n", varName->name);
238         nodePostErrorLine(node);
239         compileErrors++;
240         // Debugger();
241     }
242 }
243 
newPyrCurryArgNode()244 PyrCurryArgNode* newPyrCurryArgNode() {
245     PyrCurryArgNode* node = ALLOCNODE(PyrCurryArgNode);
246     return node;
247 }
248 
compile(PyrSlot * result)249 void PyrCurryArgNode::compile(PyrSlot* result) {
250     if (gPartiallyAppliedFunction) {
251         compileOpcode(opPushTempZeroVar, mArgNum);
252     } else {
253         error("found _ argument outside of a call.\n");
254         nodePostErrorLine((PyrParseNode*)this);
255         compileErrors++;
256     }
257 }
258 
newPyrSlotNode(PyrSlot * slot)259 PyrSlotNode* newPyrSlotNode(PyrSlot* slot) {
260     PyrSlotNode* node = ALLOCNODE(PyrSlotNode);
261     node->mSlot = *slot;
262     return node;
263 }
264 
compile(PyrSlot * result)265 void PyrSlotNode::compile(PyrSlot* result) {
266     if (mClassno == pn_LiteralNode)
267         compileLiteral(result);
268     else if (mClassno == pn_PushLitNode)
269         compilePushLit(result);
270     else if (mClassno == pn_PushNameNode)
271         compilePushVar((PyrParseNode*)this, slotRawSymbol(&mSlot));
272     else {
273         error("compilePyrSlotNode: shouldn't get here.\n");
274         dumpObjectSlot(&mSlot);
275         nodePostErrorLine((PyrParseNode*)this);
276         compileErrors++;
277         // Debugger();
278     }
279 }
280 
newPyrClassExtNode(PyrSlotNode * className,PyrMethodNode * methods)281 PyrClassExtNode* newPyrClassExtNode(PyrSlotNode* className, PyrMethodNode* methods) {
282     PyrClassExtNode* node = ALLOCNODE(PyrClassExtNode);
283     node->mClassName = className;
284 
285     node->mMethods = methods;
286     return node;
287 }
288 
compile(PyrSlot * result)289 void PyrClassExtNode::compile(PyrSlot* result) {
290     PyrClass* classobj = slotRawSymbol(&mClassName->mSlot)->u.classobj;
291     if (!classobj) {
292         const bfs::path relpath = relativeToCompileDir(bfs::path(gCompilingFileSym->name));
293         error("Class extension for nonexistent class '%s'\n     In file:'%s'\n",
294               slotRawSymbol(&mClassName->mSlot)->name, SC_Codecvt::path_to_utf8_str(relpath).c_str());
295         return;
296     }
297     gCurrentClass = classobj;
298     gCurrentMetaClass = classobj->classptr;
299     compileExtNodeMethods(this);
300 }
301 
compileExtNodeMethods(PyrClassExtNode * node)302 void compileExtNodeMethods(PyrClassExtNode* node) {
303     PyrMethodNode* method;
304     method = node->mMethods;
305     for (; method; method = (PyrMethodNode*)method->mNext) {
306         PyrSlot dummy;
307         // post("compile ext %s:%s\n",
308         method->mExtension = true;
309         compilePyrMethodNode(method, &dummy);
310     }
311     gCompilingMethod = nullptr;
312     gCompilingBlock = nullptr;
313     gPartiallyAppliedFunction = nullptr;
314     gInliningLevel = 0;
315 }
316 
newPyrClassNode(PyrSlotNode * className,PyrSlotNode * superClassName,PyrVarListNode * varlists,PyrMethodNode * methods,PyrSlotNode * indexType)317 PyrClassNode* newPyrClassNode(PyrSlotNode* className, PyrSlotNode* superClassName, PyrVarListNode* varlists,
318                               PyrMethodNode* methods, PyrSlotNode* indexType) {
319     PyrClassNode* node = ALLOCNODE(PyrClassNode);
320     node->mClassName = className;
321     node->mIndexType = indexType;
322 
323     node->mSuperClassName = superClassName;
324     node->mVarlists = varlists;
325     node->mMethods = methods;
326     node->mVarTally[varInst] = 0;
327     node->mVarTally[varClass] = 0;
328     node->mVarTally[varTemp] = 0;
329     node->mVarTally[varConst] = 0;
330     // node->mVarTally[varPool] = 0;
331     return node;
332 }
333 
compareVarDefs(PyrClassNode * node,PyrClass * classobj)334 bool compareVarDefs(PyrClassNode* node, PyrClass* classobj) {
335     int numinstvars, numclassvars;
336     int i, xinst, xclass;
337     PyrVarListNode* varlist;
338     PyrVarDefNode* vardef;
339     PyrParseNode* errnode;
340     PyrSymbol** varNames;
341     bool isIntrinsic;
342 
343     isIntrinsic = slotRawInt(&classobj->classFlags) & classIsIntrinsic;
344 
345     numinstvars = numInstVars(classobj);
346     numclassvars = numClassVars(classobj);
347     if (numinstvars == node->mVarTally[varInst] + node->mNumSuperInstVars
348         && numclassvars == node->mVarTally[varClass]) {
349         xclass = 0;
350         xinst = node->mNumSuperInstVars;
351         varlist = node->mVarlists;
352         for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) {
353             int type = varlist->mFlags;
354             if (type == varInst) {
355                 vardef = varlist->mVarDefs;
356                 varNames = slotRawSymbolArray(&classobj->instVarNames)->symbols;
357                 for (i = 0; vardef; vardef = (PyrVarDefNode*)vardef->mNext, xinst++, ++i) {
358                     if (slotRawSymbol(&vardef->mVarName->mSlot) != varNames[xinst]) {
359                         errnode = (PyrParseNode*)vardef;
360                         // post("A %s %d %d %d\n", vardef->mVarName->slotRawSymbol(&mSlot)->name,
361                         //	vardef->mVarName->slotRawSymbol(&mSlot), varNames[xinst].us, xinst);
362                         // post("A %s %s %d\n", vardef->mVarName->slotRawSymbol(&mSlot)->name,
363                         //	varNames[xinst].us->name, xinst);
364                         goto differExit;
365                     }
366                 }
367             } else if (type == varClass) {
368                 vardef = varlist->mVarDefs;
369                 varNames = slotRawSymbolArray(&classobj->classVarNames)->symbols;
370                 for (i = 0; vardef && xclass < numclassvars; vardef = (PyrVarDefNode*)vardef->mNext, xclass++, ++i) {
371                     if (slotRawSymbol(&vardef->mVarName->mSlot) != varNames[xclass]) {
372                         errnode = (PyrParseNode*)vardef;
373                         // post("B %d %d %d\n", vardef->mVarName->slotRawSymbol(&mSlot), varNames[xclass].us, xclass);
374                         goto differExit;
375                     }
376                 }
377             }
378         }
379     } else {
380         // post("C %d %d %d   %d %d\n", numinstvars, node->mVarTally[varInst], node->mNumSuperInstVars,
381         //	numclassvars, node->mVarTally[varClass]);
382         errnode = (node->mVarlists ? (PyrParseNode*)node->mVarlists : (PyrParseNode*)node->mClassName);
383         goto differExit;
384     }
385     return false;
386 
387 differExit:
388     if (isIntrinsic) {
389         error("You may not change variable definitions of intrinsic classes.\n");
390         nodePostErrorLine(errnode);
391         compileErrors++;
392     }
393     return true;
394 }
395 
countClassVarDefs(PyrClassNode * node,int * numClassMethods,int * numInstMethods)396 void countClassVarDefs(PyrClassNode* node, int* numClassMethods, int* numInstMethods) {
397     PyrVarListNode* varlist;
398     PyrVarDefNode* vardef;
399 
400     //*numClassMethods = 0;
401     //*numInstMethods = 0;
402 
403     node->mVarTally[varInst] = 0;
404     node->mVarTally[varClass] = 0;
405     node->mVarTally[varTemp] = 0;
406     node->mVarTally[varConst] = 0;
407 
408     // count number of variables of each type
409     varlist = node->mVarlists;
410     for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) {
411         int type = varlist->mFlags;
412         vardef = varlist->mVarDefs;
413         for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) {
414             node->mVarTally[type]++;
415             if (type == varClass) {
416                 if (vardef->mFlags & rwReadOnly) {
417                     *numClassMethods = *numClassMethods + 1;
418                 }
419                 if (vardef->mFlags & rwWriteOnly) {
420                     *numClassMethods = *numClassMethods + 1;
421                 }
422             } else if (type == varInst) {
423                 if (vardef->mFlags & rwReadOnly) {
424                     *numInstMethods = *numInstMethods + 1;
425                 }
426                 if (vardef->mFlags & rwWriteOnly) {
427                     *numInstMethods = *numInstMethods + 1;
428                 }
429             }
430         }
431     }
432 }
433 
countNodeMethods(PyrClassNode * node,int * numClassMethods,int * numInstMethods)434 void countNodeMethods(PyrClassNode* node, int* numClassMethods, int* numInstMethods) {
435     // count methods
436     PyrMethodNode* method;
437     //*numClassMethods = 0;
438     //*numInstMethods = 0;
439     method = node->mMethods;
440     for (; method; method = (PyrMethodNode*)method->mNext) {
441         if (method->mIsClassMethod)
442             *numClassMethods = *numClassMethods + 1;
443         else
444             *numInstMethods = *numInstMethods + 1;
445     }
446 }
447 
compileNodeMethods(PyrClassNode * node)448 void compileNodeMethods(PyrClassNode* node) {
449     PyrMethodNode* method;
450     method = node->mMethods;
451     for (; method; method = (PyrMethodNode*)method->mNext) {
452         PyrSlot dummy;
453         method->mExtension = false;
454         compilePyrMethodNode(method, &dummy);
455     }
456     gCompilingMethod = nullptr;
457     gCompilingBlock = nullptr;
458     gPartiallyAppliedFunction = nullptr;
459     gInliningLevel = 0;
460 }
461 
getNodeSuperclass(PyrClassNode * node)462 PyrClass* getNodeSuperclass(PyrClassNode* node) {
463     PyrClass* superclassobj = nullptr;
464     //	postfl("getNodeSuperclass node %d\n", node);
465     //	postfl("getNodeSuperclass node->mSuperClassName %d\n", node->mSuperClassName);
466     //	postfl("getNodeSuperclass node->mSuperClassName->mSlot.utag %d\n",
467     //		node->mSuperClassName->mSlot.utag);
468     if (node->mSuperClassName && IsSym(&node->mSuperClassName->mSlot)) {
469         superclassobj = slotRawSymbol(&node->mSuperClassName->mSlot)->u.classobj;
470         if (superclassobj == nullptr) {
471             error("Cannot find superclass '%s' for class '%s'\n", slotSymString(&node->mSuperClassName->mSlot),
472                   slotSymString(&node->mClassName->mSlot));
473             nodePostErrorLine((PyrParseNode*)node->mSuperClassName);
474             superclassobj = (PyrClass*)-1;
475             compileErrors++;
476         }
477     } else {
478         if (slotRawSymbol(&node->mClassName->mSlot) != s_object) {
479             superclassobj = class_object;
480         } // else this is object and there is no superclass
481     }
482     return superclassobj;
483 }
484 
fillClassPrototypes(PyrClassNode * node,PyrClass * classobj,PyrClass * superclassobj)485 void fillClassPrototypes(PyrClassNode* node, PyrClass* classobj, PyrClass* superclassobj) {
486     PyrVarListNode* varlist;
487     PyrVarDefNode* vardef;
488     PyrSlot *islot, *cslot, *kslot;
489     PyrSymbol **inameslot, **cnameslot, **knameslot;
490     PyrClass* metaclassobj;
491     PyrMethod* method;
492     PyrMethodRaw* methraw;
493     int instVarIndex, classVarIndex;
494 
495     // copy superclass's prototype to here
496     if (superclassobj && NotNil(&superclassobj->iprototype) && slotRawObject(&superclassobj->iprototype)->size) {
497         memcpy(slotRawObject(&classobj->iprototype)->slots, slotRawObject(&superclassobj->iprototype)->slots,
498                sizeof(PyrSlot) * slotRawObject(&superclassobj->iprototype)->size);
499         // slotRawObject(&classobj->iprototype)->size = slotRawObject(&superclassobj->iprototype)->size;
500         slotRawObject(&classobj->iprototype)->size = node->mNumSuperInstVars;
501 
502         memcpy(slotRawSymbolArray(&classobj->instVarNames)->symbols,
503                slotRawSymbolArray(&superclassobj->instVarNames)->symbols,
504                sizeof(PyrSymbol*) * slotRawObject(&superclassobj->instVarNames)->size);
505         // slotRawObject(&classobj->instVarNames)->size = slotRawObject(&superclassobj->iprototype)->size;
506         slotRawObject(&classobj->instVarNames)->size = node->mNumSuperInstVars;
507     }
508     // fill the class' own part of prototypes
509     metaclassobj = classobj->classptr;
510     varlist = node->mVarlists;
511     if (NotNil(&classobj->iprototype)) {
512         islot = slotRawObject(&classobj->iprototype)->slots + node->mNumSuperInstVars;
513     }
514     if (NotNil(&classobj->cprototype)) {
515         cslot = slotRawObject(&classobj->cprototype)->slots;
516     }
517     if (NotNil(&classobj->constValues)) {
518         kslot = slotRawObject(&classobj->constValues)->slots;
519     }
520     if (NotNil(&classobj->instVarNames)) {
521         inameslot = slotRawSymbolArray(&classobj->instVarNames)->symbols + node->mNumSuperInstVars;
522     }
523     if (NotNil(&classobj->classVarNames)) {
524         cnameslot = slotRawSymbolArray(&classobj->classVarNames)->symbols;
525     }
526     if (NotNil(&classobj->constNames)) {
527         knameslot = slotRawSymbolArray(&classobj->constNames)->symbols;
528     }
529     instVarIndex = node->mNumSuperInstVars;
530     classVarIndex = 0;
531     for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) {
532         int type = varlist->mFlags;
533         switch (type) {
534         case varInst:
535             vardef = varlist->mVarDefs;
536             for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) {
537                 PyrSlot litslot;
538                 compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litslot);
539                 *islot++ = litslot;
540                 slotRawObject(&classobj->iprototype)->size++;
541                 *inameslot++ = slotRawSymbol(&vardef->mVarName->mSlot);
542                 slotRawSymbolArray(&classobj->instVarNames)->size++;
543                 if (vardef->mFlags & rwReadOnly) {
544                     // create getter method
545                     method = newPyrMethod();
546                     methraw = METHRAW(method);
547                     methraw->unused1 = 0;
548                     methraw->unused2 = 0;
549                     methraw->numargs = 1;
550                     methraw->numvars = 0;
551                     methraw->posargs = 1;
552                     methraw->varargs = 0;
553                     methraw->numtemps = 1;
554                     methraw->popSize = 0;
555                     SetNil(&method->contextDef);
556                     SetNil(&method->varNames);
557                     SetObject(&method->ownerclass, classobj);
558                     if (gCompilingFileSym)
559                         SetSymbol(&method->filenameSym, gCompilingFileSym);
560                     SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset);
561                     slotCopy(&method->name, &vardef->mVarName->mSlot);
562                     methraw->methType = methReturnInstVar;
563                     methraw->specialIndex = instVarIndex;
564                     addMethod(classobj, method);
565                 }
566                 if (vardef->mFlags & rwWriteOnly) {
567                     char setterName[256];
568                     PyrSymbol* setterSym;
569                     sprintf(setterName, "%s_", slotRawSymbol(&vardef->mVarName->mSlot)->name);
570                     // underscore = strcpy(setterName, slotRawSymbol(&vardef->mVarName->mSlot)->name);
571                     // underscore[0] = '_';
572                     // underscore[1] = 0;
573                     setterSym = getsym(setterName);
574                     // create setter method
575                     method = newPyrMethod();
576                     methraw = METHRAW(method);
577                     methraw->unused1 = 0;
578                     methraw->unused2 = 0;
579                     methraw->numargs = 2;
580                     methraw->numvars = 0;
581                     methraw->posargs = 2;
582                     methraw->varargs = 0;
583                     methraw->numtemps = 2;
584                     methraw->popSize = 1;
585                     SetNil(&method->contextDef);
586                     SetNil(&method->varNames);
587                     SetObject(&method->ownerclass, classobj);
588                     SetSymbol(&method->name, setterSym);
589                     if (gCompilingFileSym)
590                         SetSymbol(&method->filenameSym, gCompilingFileSym);
591                     SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset);
592 
593                     methraw->methType = methAssignInstVar;
594                     methraw->specialIndex = instVarIndex;
595                     addMethod(classobj, method);
596                 }
597                 instVarIndex++;
598             }
599             break;
600         case varClass:
601             vardef = varlist->mVarDefs;
602             for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) {
603                 PyrSlot litslot;
604                 compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litslot);
605                 *cslot++ = litslot;
606                 slotRawObject(&classobj->cprototype)->size++;
607                 *cnameslot++ = slotRawSymbol(&vardef->mVarName->mSlot);
608                 slotRawSymbolArray(&classobj->classVarNames)->size++;
609                 if (vardef->mFlags & rwReadOnly) {
610                     // create getter method
611                     method = newPyrMethod();
612                     methraw = METHRAW(method);
613                     methraw->unused1 = 0;
614                     methraw->unused2 = 0;
615                     methraw->numargs = 1;
616                     methraw->numvars = 0;
617                     methraw->posargs = 1;
618                     methraw->varargs = 0;
619                     methraw->numtemps = 1;
620                     methraw->popSize = 0;
621                     SetNil(&method->contextDef);
622                     SetNil(&method->varNames);
623                     SetObject(&method->ownerclass, metaclassobj);
624                     slotCopy(&method->name, &vardef->mVarName->mSlot);
625                     SetSymbol(&method->selectors, slotRawSymbol(&classobj->name));
626                     if (gCompilingFileSym)
627                         SetSymbol(&method->filenameSym, gCompilingFileSym);
628                     SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset);
629 
630                     methraw->methType = methReturnClassVar;
631                     methraw->specialIndex = classVarIndex + slotRawInt(&classobj->classVarIndex);
632                     addMethod(metaclassobj, method);
633                 }
634                 if (vardef->mFlags & rwWriteOnly) {
635                     char setterName[256];
636                     PyrSymbol* setterSym;
637                     sprintf(setterName, "%s_", slotRawSymbol(&vardef->mVarName->mSlot)->name);
638                     // underscore = strcpy(setterName, slotRawSymbol(&vardef->mVarName->mSlot)->name);
639                     // underscore[0] = '_';
640                     // underscore[1] = 0;
641                     setterSym = getsym(setterName);
642                     // create setter method
643                     method = newPyrMethod();
644                     methraw = METHRAW(method);
645                     methraw->numargs = 2;
646                     methraw->numvars = 0;
647                     methraw->posargs = 2;
648                     methraw->varargs = 0;
649                     methraw->numtemps = 2;
650                     methraw->popSize = 1;
651                     SetNil(&method->contextDef);
652                     SetNil(&method->varNames);
653                     SetObject(&method->ownerclass, metaclassobj);
654                     SetSymbol(&method->name, setterSym);
655                     SetSymbol(&method->selectors, slotRawSymbol(&classobj->name));
656                     if (gCompilingFileSym)
657                         SetSymbol(&method->filenameSym, gCompilingFileSym);
658                     SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset);
659 
660                     methraw->methType = methAssignClassVar;
661                     methraw->specialIndex = classVarIndex + slotRawInt(&classobj->classVarIndex);
662                     addMethod(metaclassobj, method);
663                 }
664                 classVarIndex++;
665             }
666             break;
667         case varConst:
668             vardef = varlist->mVarDefs;
669             for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) {
670                 PyrSlot litslot;
671                 compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litslot);
672                 *kslot++ = litslot;
673                 slotRawObject(&classobj->constValues)->size++;
674                 *knameslot++ = slotRawSymbol(&vardef->mVarName->mSlot);
675                 slotRawSymbolArray(&classobj->constNames)->size++;
676                 if (vardef->mFlags & rwReadOnly) {
677                     // create getter method
678                     method = newPyrMethod();
679                     methraw = METHRAW(method);
680                     methraw->unused1 = 0;
681                     methraw->unused2 = 0;
682                     methraw->numargs = 1;
683                     methraw->numvars = 0;
684                     methraw->posargs = 1;
685                     methraw->varargs = 0;
686                     methraw->numtemps = 1;
687                     methraw->popSize = 0;
688                     SetNil(&method->contextDef);
689                     SetNil(&method->varNames);
690                     SetObject(&method->ownerclass, metaclassobj);
691                     slotCopy(&method->name, &vardef->mVarName->mSlot);
692                     if (gCompilingFileSym)
693                         SetSymbol(&method->filenameSym, gCompilingFileSym);
694                     SetInt(&method->charPos, linestarts[vardef->mVarName->mLineno] + errCharPosOffset);
695 
696                     methraw->methType = methReturnLiteral;
697                     slotCopy(&method->selectors, &litslot);
698                     addMethod(metaclassobj, method);
699                 }
700             }
701             break;
702         }
703     }
704 }
705 
getIndexType(PyrClassNode * classnode)706 int getIndexType(PyrClassNode* classnode) {
707     PyrSlotNode* node;
708     int res;
709 
710     node = classnode->mIndexType;
711     if (node == nullptr)
712         res = obj_notindexed;
713     else {
714         char* name;
715         name = slotRawSymbol(&node->mSlot)->name;
716         if (strcmp(name, "slot") == 0)
717             res = obj_slot;
718         else if (strcmp(name, "double") == 0)
719             res = obj_double;
720         else if (strcmp(name, "float") == 0)
721             res = obj_float;
722         else if (strcmp(name, "int32") == 0)
723             res = obj_int32;
724         else if (strcmp(name, "int16") == 0)
725             res = obj_int16;
726         else if (strcmp(name, "int8") == 0)
727             res = obj_int8;
728         else if (strcmp(name, "char") == 0)
729             res = obj_char;
730         else if (strcmp(name, "symbol") == 0)
731             res = obj_symbol;
732         else {
733             error("Illegal indexed type. Must be one of:\n"
734                   "   slot, double, float, int8, int16, int32, char\n");
735             res = obj_slot;
736             compileErrors++;
737         }
738     }
739     return res;
740 }
741 
compile(PyrSlot * result)742 void PyrClassNode::compile(PyrSlot* result) {
743     PyrClass *classobj, *superclassobj, *metaclassobj;
744     int numClassMethods, numInstMethods;
745     bool isIntrinsic;
746     bool varsDiffer, superclassesDiffer, indexTypesDiffer;
747     bool shouldRecompileSubclasses = false;
748     int indexType;
749 
750     // find num instvars in superclass
751     // postfl("class '%s'\n", slotRawSymbol(&mClassName->mSlot)->name);
752     superclassobj = getNodeSuperclass(this);
753     indexType = getIndexType(this);
754     // postfl("%s %d\n", slotRawSymbol(&mClassName->mSlot)->name, indexType);
755 
756     if ((size_t)superclassobj == -1) {
757         // redundant error message removed:
758         // error("Can't find superclass of '%s'\n", slotRawSymbol(&mClassName->mSlot)->name);
759         // nodePostErrorLine(node);
760         return; // can't find superclass
761     }
762     mNumSuperInstVars = numSuperInstVars(superclassobj);
763 
764     numClassMethods = 0;
765     numInstMethods = 0;
766     countClassVarDefs(this, &numClassMethods, &numInstMethods);
767     // postfl("accessor methods %d %d\n", numClassMethods, numInstMethods);
768     countNodeMethods(this, &numClassMethods, &numInstMethods);
769     // postfl("total methods %d %d\n", numClassMethods, numInstMethods);
770 
771     // get or make a class object
772     // see if it already exists
773     classobj = slotRawSymbol(&mClassName->mSlot)->u.classobj;
774     if (classobj) {
775         // deal with intrinsic classes or other classes being recompiled here.
776         // recompile of subclasses not necessary if inst and class vars are
777         // unchanged.
778         metaclassobj = (PyrClass*)classobj->classptr;
779         isIntrinsic = slotRawInt(&classobj->classFlags) & classIsIntrinsic;
780 
781         varsDiffer = compareVarDefs(this, classobj);
782         if (varsDiffer) {
783             if (isIntrinsic) {
784                 // error("Class '%s' declaration doesn't match intrinsic definition.\n",
785                 //	slotRawSymbol(&mClassName->mSlot)->name);
786                 return;
787             } else {
788                 shouldRecompileSubclasses = true;
789             }
790         }
791         superclassesDiffer = superclassobj != slotRawSymbol(&classobj->superclass)->u.classobj;
792         indexTypesDiffer = indexType != slotRawInt(&classobj->instanceFormat);
793         // postfl("%d %d %d\n", indexType, slotRawInt(&classobj->instanceFormat));
794         // if (varsDiffer || superclassesDiffer || indexTypesDiffer) {
795         if (varsDiffer || superclassesDiffer || indexTypesDiffer) {
796             if (isIntrinsic) {
797                 if (superclassesDiffer) {
798                     error("Superclass of '%s' does not match intrinsic definition.\n",
799                           slotRawSymbol(&mClassName->mSlot)->name);
800                     nodePostErrorLine((PyrParseNode*)(mSuperClassName ? mSuperClassName : mClassName));
801                     compileErrors++;
802                 }
803                 if (indexTypesDiffer) {
804                     error("Index type of '%s' does not match intrinsic definition.\n",
805                           slotRawSymbol(&mClassName->mSlot)->name);
806                     nodePostErrorLine((indexType ? (PyrParseNode*)mIndexType : (PyrParseNode*)mClassName));
807                     compileErrors++;
808                 }
809                 error("Class '%s' declaration doesn't match intrinsic definition.\n",
810                       slotRawSymbol(&mClassName->mSlot)->name);
811                 return;
812             } else {
813                 shouldRecompileSubclasses = true;
814             }
815         }
816         // reallocate fields in the class object
817         reallocClassObj(metaclassobj, classClassNumInstVars, 0, 0, numClassMethods, indexType, 0);
818 
819         // postfl("^3 %d %d\n", metaclassobj, class_class);
820         // postfl("^4 %d %d\n", slotRawObject(&metaclassobj->iprototype), slotRawObject(&class_class->iprototype));
821         memcpy(slotRawObject(&metaclassobj->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots,
822                sizeof(PyrSlot) * classClassNumInstVars);
823         memcpy(slotRawSymbolArray(&metaclassobj->instVarNames)->symbols,
824                slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars);
825         slotRawObject(&metaclassobj->iprototype)->size = classClassNumInstVars;
826         slotRawSymbolArray(&metaclassobj->instVarNames)->size = classClassNumInstVars;
827 
828         reallocClassObj(classobj, mVarTally[varInst] + mNumSuperInstVars, mVarTally[varClass], mVarTally[varConst],
829                         numInstMethods, indexType, 0);
830 
831     } else {
832         PyrSymbol *superClassName, *metaClassName, *metaSuperClassName;
833 
834         superClassName = superclassobj ? slotRawSymbol(&superclassobj->name) : nullptr;
835         metaClassName = getmetasym(slotRawSymbol(&mClassName->mSlot)->name);
836         metaClassName->flags |= sym_MetaClass;
837         metaSuperClassName = superClassName ? getmetasym(superClassName->name) : nullptr;
838 
839         metaclassobj = newClassObj(class_class, metaClassName, metaSuperClassName, classClassNumInstVars, 0, 0,
840                                    numClassMethods, indexType, 0);
841         // test
842         // postfl("^1 %d %d\n", metaclassobj, class_class);
843         // postfl("^2 %d %d\n", slotRawObject(&metaclassobj->iprototype), slotRawObject(&class_class->iprototype));
844 
845         memcpy(slotRawObject(&metaclassobj->iprototype)->slots, slotRawObject(&class_class->iprototype)->slots,
846                sizeof(PyrSlot) * classClassNumInstVars);
847         memcpy(slotRawSymbolArray(&metaclassobj->instVarNames)->symbols,
848                slotRawSymbolArray(&class_class->instVarNames)->symbols, sizeof(PyrSymbol*) * classClassNumInstVars);
849         slotRawObject(&metaclassobj->iprototype)->size = classClassNumInstVars;
850         slotRawObject(&metaclassobj->instVarNames)->size = classClassNumInstVars;
851         // end test
852         classobj = newClassObj(metaclassobj, slotRawSymbol(&mClassName->mSlot), superClassName,
853                                mVarTally[varInst] + mNumSuperInstVars, mVarTally[varClass], mVarTally[varConst],
854                                numInstMethods, indexType, 0);
855     }
856     gCurrentClass = classobj;
857     gCurrentMetaClass = metaclassobj;
858     if (gCompilingFileSym) {
859         SetSymbol(&classobj->filenameSym, gCompilingFileSym);
860         SetInt(&classobj->charPos, linestarts[mClassName->mLineno] + errCharPosOffset);
861         SetSymbol(&metaclassobj->filenameSym, gCompilingFileSym);
862         SetInt(&metaclassobj->charPos, linestarts[mClassName->mLineno] + errCharPosOffset);
863     } else {
864         SetNil(&classobj->filenameSym);
865         SetNil(&metaclassobj->filenameSym);
866     }
867 
868     // fill inst and class prototypes
869     fillClassPrototypes(this, classobj, superclassobj);
870 
871     // compile methods
872     compileNodeMethods(this);
873 
874     // recompileSubclasses
875     if (shouldRecompileSubclasses) {
876         recompileSubclasses(classobj);
877     }
878 }
879 
recompileSubclasses(PyrClass * classobj)880 void recompileSubclasses(PyrClass* classobj) {}
881 
882 #if 0
883 void catVarLists(PyrVarListNode *varlist);
884 void catVarLists(PyrVarListNode *varlist)
885 {
886 	PyrVarListNode *prevvarlist;
887 	PyrVarDefNode *vardef, *lastvardef;
888 
889 	if (varlist) {
890 		// find end of this list
891 		vardef = varlist->mVarDefs;
892 		for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) {
893 			lastvardef = vardef;
894 		}
895 		prevvarlist = varlist;
896 		varlist = (PyrVarListNode*)varlist->mNext;
897 
898 		for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) {
899 			vardef = varlist->mVarDefs;
900 			if (lastvardef) {
901 				lastvardef->mNext = (PyrParseNode*)vardef;
902 			} else {
903 				prevvarlist->mVarDefs = vardef;
904 			}
905 			// find end of this list
906 			for (; vardef; vardef = (PyrVarDefNode*)vardef->mNext) {
907 				lastvardef = vardef;
908 			}
909 		}
910 	}
911 }
912 
913 #else
914 
915 void catVarLists(PyrVarListNode* varlist);
catVarLists(PyrVarListNode * varlist)916 void catVarLists(PyrVarListNode* varlist) {
917     PyrVarListNode* prevvarlist;
918     PyrVarDefNode *vardef, *lastvardef;
919 
920     if (varlist) {
921         // find end of this list
922         vardef = varlist->mVarDefs;
923         lastvardef = (PyrVarDefNode*)vardef->mTail;
924         prevvarlist = varlist;
925         varlist = (PyrVarListNode*)varlist->mNext;
926 
927         for (; varlist; varlist = (PyrVarListNode*)varlist->mNext) {
928             vardef = varlist->mVarDefs;
929             lastvardef->mNext = (PyrParseNode*)vardef;
930 
931             // find end of this list
932             lastvardef = (PyrVarDefNode*)vardef->mTail;
933         }
934     }
935 }
936 #endif
937 
newPyrMethodNode(PyrSlotNode * methodName,PyrSlotNode * primitiveName,PyrArgListNode * arglist,PyrVarListNode * varlist,PyrParseNode * body,int isClassMethod)938 PyrMethodNode* newPyrMethodNode(PyrSlotNode* methodName, PyrSlotNode* primitiveName, PyrArgListNode* arglist,
939                                 PyrVarListNode* varlist, PyrParseNode* body, int isClassMethod) {
940     PyrMethodNode* node = ALLOCNODE(PyrMethodNode);
941     node->mMethodName = methodName;
942     node->mPrimitiveName = primitiveName;
943     node->mArglist = arglist;
944     catVarLists(varlist);
945     node->mVarlist = varlist;
946     node->mBody = body;
947     node->mIsClassMethod = isClassMethod;
948     return node;
949 }
950 
951 enum { push_Normal, push_AllArgs, push_AllButFirstArg, push_AllButFirstArg2 };
952 
953 int checkPushAllArgs(PyrParseNode* actualArg, int numArgs);
checkPushAllArgs(PyrParseNode * actualArg,int numArgs)954 int checkPushAllArgs(PyrParseNode* actualArg, int numArgs) {
955     PyrBlock* block;
956     PyrPushNameNode* nameNode;
957     block = gCompilingBlock;
958     int i;
959 
960     // if (strcmp("ar", slotRawSymbol(&gCompilingMethod->name)->name)==0) Debugger();
961     if (actualArg->mClassno != pn_PushNameNode) {
962         if (numArgs < 3) {
963             return push_Normal;
964         }
965         actualArg = actualArg->mNext;
966         for (i = 1; i < numArgs; ++i) {
967             if (actualArg->mClassno != pn_PushNameNode) {
968                 return push_Normal;
969             }
970             nameNode = (PyrPushNameNode*)actualArg;
971             if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbolArray(&block->argNames)->symbols[i]) {
972                 return push_Normal;
973             }
974 
975             actualArg = actualArg->mNext;
976         }
977         return push_AllButFirstArg;
978 
979     } else {
980         for (i = 0; i < numArgs; ++i) {
981             if (actualArg->mClassno != pn_PushNameNode) {
982                 return push_Normal;
983             }
984             nameNode = (PyrPushNameNode*)actualArg;
985             if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbolArray(&block->argNames)->symbols[i]) {
986                 return push_Normal;
987             }
988             actualArg = actualArg->mNext;
989         }
990         return push_AllArgs;
991     }
992 }
993 
994 
995 int checkPushAllButFirstTwoArgs(PyrParseNode* actualArg, int numArgs);
checkPushAllButFirstTwoArgs(PyrParseNode * actualArg,int numArgs)996 int checkPushAllButFirstTwoArgs(PyrParseNode* actualArg, int numArgs) {
997     PyrBlock* block;
998     PyrPushNameNode* nameNode;
999     block = gCompilingBlock;
1000     int i;
1001 
1002     if (numArgs >= 2) {
1003         actualArg = actualArg->mNext;
1004         actualArg = actualArg->mNext;
1005         for (i = 1; i < numArgs; ++i) {
1006             if (actualArg->mClassno != pn_PushNameNode) {
1007                 return push_Normal;
1008             }
1009             nameNode = (PyrPushNameNode*)actualArg;
1010             if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbolArray(&block->argNames)->symbols[i]) {
1011                 return push_Normal;
1012             }
1013 
1014             actualArg = actualArg->mNext;
1015         }
1016         return push_AllButFirstArg2;
1017     }
1018     return push_Normal;
1019 }
1020 
compareCallArgs(PyrMethodNode * node,PyrCallNode * cnode,int * varIndex,PyrClass ** specialClass)1021 int compareCallArgs(PyrMethodNode* node, PyrCallNode* cnode, int* varIndex, PyrClass** specialClass) {
1022     int i, numFormalArgs, numActualArgs;
1023     int special, varType, varLevel;
1024     PyrParseNode* actualArg;
1025     PyrVarDefNode* formalArg;
1026     PyrPushNameNode* nameNode;
1027 
1028     // fail if has a rest arg .. too much trouble?
1029     if (node->mArglist && node->mArglist->mRest) {
1030         return methNormal;
1031     }
1032 
1033     // check first actual arg is 'this'
1034     actualArg = cnode->mArglist;
1035     if (actualArg->mClassno != pn_PushNameNode) {
1036         return methNormal;
1037     }
1038     nameNode = (PyrPushNameNode*)actualArg;
1039     if (slotRawSymbol(&nameNode->mSlot) == s_this) {
1040         special = methRedirect;
1041     } else if (slotRawSymbol(&nameNode->mSlot) == s_super) {
1042         special = methRedirectSuper;
1043     } else {
1044         bool varFound;
1045         PyrClass* classobj;
1046 
1047         classobj = gCompilingClass;
1048         varFound = findVarName(gCompilingBlock, &classobj, slotRawSymbol(&nameNode->mSlot), &varType, &varLevel,
1049                                varIndex, nullptr);
1050         if (!varFound)
1051             return methNormal;
1052 
1053         if (varType == varInst)
1054             special = methForwardInstVar;
1055         else if (varType == varClass) {
1056             special = methForwardClassVar;
1057             *varIndex += slotRawInt(&classobj->classVarIndex);
1058             *specialClass = classobj;
1059         } else
1060             return methNormal;
1061     }
1062 
1063     actualArg = actualArg->mNext;
1064     numActualArgs = nodeListLength((PyrParseNode*)cnode->mArglist);
1065 
1066     if (!node->mArglist) {
1067         numFormalArgs = 1;
1068         if (numActualArgs != numFormalArgs) {
1069             return methNormal;
1070         }
1071     } else {
1072         numFormalArgs = 1 + nodeListLength((PyrParseNode*)node->mArglist->mVarDefs);
1073         if (numActualArgs != numFormalArgs) {
1074             return methNormal;
1075         }
1076 
1077         formalArg = node->mArglist->mVarDefs;
1078         for (i = 0; i < numActualArgs - 1; ++i) {
1079             if (actualArg->mClassno != pn_PushNameNode) {
1080                 return methNormal;
1081             }
1082 
1083             nameNode = (PyrPushNameNode*)actualArg;
1084             if (slotRawSymbol(&nameNode->mSlot) != slotRawSymbol(&formalArg->mVarName->mSlot)) {
1085                 return methNormal;
1086             }
1087 
1088             formalArg = (PyrVarDefNode*)formalArg->mNext;
1089             actualArg = actualArg->mNext;
1090         }
1091     }
1092     /*
1093     if (special == methForwardInstVar) {
1094         postfl("methForwardInstVar %s:%s  formal %d  actual %d\n", slotRawSymbol(&gCompilingClass->name)->name,
1095             slotRawSymbol(&gCompilingMethod->name)->name, numFormalArgs, numActualArgs);
1096     }
1097     if (special == methForwardClassVar) {
1098         postfl("methForwardClassVar %s:%s  formal %d  actual %d\n", slotRawSymbol(&gCompilingClass->name)->name,
1099             slotRawSymbol(&gCompilingMethod->name)->name, numFormalArgs, numActualArgs);
1100     }
1101     if (special == methRedirectSuper) {
1102         postfl("methRedirectSuper %s:%s  formal %d  actual %d\n", slotRawSymbol(&gCompilingClass->name)->name,
1103             slotRawSymbol(&gCompilingMethod->name)->name, numFormalArgs, numActualArgs);
1104     }
1105     */
1106 
1107     //	if (special == methTempDelegate) {
1108     //		postfl("methTempDelegate %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name,
1109     //			slotRawSymbol(&gCompilingMethod->name)->name);
1110     //	}
1111     return special;
1112 }
1113 
installByteCodes(PyrBlock * block)1114 void installByteCodes(PyrBlock* block) {
1115     PyrInt8Array* byteArray;
1116     long length, flags;
1117     ByteCodes byteCodes;
1118     byteCodes = getByteCodes();
1119     if (byteCodes) {
1120         length = byteCodeLength(byteCodes);
1121         if (length) {
1122             flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
1123             byteArray = newPyrInt8Array(compileGC(), length, flags, false);
1124             copyByteCodes(byteArray->b, byteCodes);
1125             byteArray->size = length;
1126             freeByteCodes(byteCodes);
1127             SetObject(&block->code, byteArray);
1128         } else {
1129             error("installByteCodes: zero length byte codes\n");
1130         }
1131     } else {
1132         error("installByteCodes: NULL byte codes\n");
1133     }
1134 }
1135 
1136 PyrMethod* initPyrMethod(PyrMethod* method);
1137 
compilePyrMethodNode(PyrMethodNode * node,PyrSlot * result)1138 void compilePyrMethodNode(PyrMethodNode* node, PyrSlot* result) { node->compile(result); }
1139 
compile(PyrSlot * result)1140 void PyrMethodNode::compile(PyrSlot* result) {
1141     PyrMethod *method, *oldmethod;
1142     PyrMethodRaw* methraw;
1143     int i, j, numArgs, numVars, methType, funcVarArgs, firstKeyIndex;
1144     int index, numSlots, numArgNames;
1145     bool hasPrimitive = false;
1146     bool hasVarExprs = false;
1147     PyrVarDefNode* vardef;
1148     PyrObject* proto;
1149     PyrSymbolArray *argNames, *varNames;
1150 
1151     SetTailBranch branch(false);
1152 
1153     // postfl("->method '%s'\n", slotRawSymbol(&mMethodName->mSlot)->name);
1154     gCompilingClass = mIsClassMethod ? gCurrentMetaClass : gCurrentClass;
1155     oldmethod = classFindDirectMethod(gCompilingClass, slotRawSymbol(&mMethodName->mSlot));
1156 
1157     if (oldmethod && !mExtension) {
1158         error("Method %s:%s already defined.\n", slotRawSymbol(&slotRawClass(&oldmethod->ownerclass)->name)->name,
1159               slotRawSymbol(&oldmethod->name)->name);
1160         nodePostErrorLine((PyrParseNode*)mMethodName);
1161         compileErrors++;
1162         return;
1163     }
1164 
1165     if (oldmethod) {
1166         ++numOverwrites;
1167 
1168         // accumulate overwrite message onto the string buffer
1169         overwriteMsg.append(slotRawSymbol(&slotRawClass(&oldmethod->ownerclass)->name)->name)
1170             .append(":")
1171             .append(slotRawSymbol(&oldmethod->name)->name)
1172             .append("\t")
1173             .append(gCompilingFileSym->name)
1174             .append("\t")
1175             .append(slotRawSymbol(&oldmethod->filenameSym)->name)
1176             .append("\n");
1177 
1178         method = oldmethod;
1179         freePyrSlot(&method->code);
1180         freePyrSlot(&method->selectors);
1181         freePyrSlot(&method->prototypeFrame);
1182         freePyrSlot(&method->argNames);
1183         freePyrSlot(&method->varNames);
1184         initPyrMethod(method);
1185     } else {
1186         method = newPyrMethod();
1187     }
1188     SetObject(&method->ownerclass, gCompilingClass);
1189 
1190     methraw = METHRAW(method);
1191     methraw->unused1 = 0;
1192     methraw->unused2 = 0;
1193 
1194     // postfl("method %p raw %p\n", method, methraw);
1195     method->contextDef = o_nil;
1196     method->name = mMethodName->mSlot;
1197     if (gCompilingFileSym)
1198         SetSymbol(&method->filenameSym, gCompilingFileSym);
1199     SetInt(&method->charPos, linestarts[mMethodName->mLineno] + errCharPosOffset);
1200     if (mPrimitiveName) {
1201         hasPrimitive = true;
1202         method->primitiveName = mPrimitiveName->mSlot;
1203         methraw->specialIndex = slotRawSymbol(&mPrimitiveName->mSlot)->u.index;
1204     }
1205     gCompilingBlock = (PyrBlock*)method;
1206     gCompilingMethod = (PyrMethod*)method;
1207     gPartiallyAppliedFunction = nullptr;
1208     gInliningLevel = 0;
1209 
1210     methraw->needsHeapContext = 0;
1211 
1212     methraw->varargs = funcVarArgs = (mArglist && mArglist->mRest) ? 1 : 0;
1213     numArgs = mArglist ? nodeListLength((PyrParseNode*)mArglist->mVarDefs) + 1 : 1;
1214     numVars = mVarlist ? nodeListLength((PyrParseNode*)mVarlist->mVarDefs) : 0;
1215 
1216     numSlots = numArgs + funcVarArgs + numVars;
1217     methraw->frameSize = (numSlots + FRAMESIZE) * sizeof(PyrSlot);
1218 
1219     methraw->numargs = numArgs;
1220     methraw->numvars = numVars;
1221     methraw->posargs = numArgs + funcVarArgs;
1222     methraw->numtemps = numSlots;
1223     methraw->popSize = numSlots - 1;
1224     firstKeyIndex = numArgs + funcVarArgs;
1225 
1226     numArgNames = methraw->posargs;
1227 
1228     if (numSlots == 1) {
1229         slotCopy(&method->argNames, &o_argnamethis);
1230         slotCopy(&method->prototypeFrame, &o_onenilarray);
1231     } else {
1232         argNames = newPyrSymbolArray(nullptr, numArgNames, obj_permanent | obj_immutable, false);
1233         argNames->size = numArgNames;
1234         SetObject(&method->argNames, argNames);
1235 
1236         proto = newPyrArray(nullptr, numSlots, obj_permanent | obj_immutable, false);
1237         proto->size = numSlots;
1238         SetObject(&method->prototypeFrame, proto);
1239 
1240         // declare args
1241         slotRawSymbolArray(&method->argNames)->symbols[0] = s_this;
1242         if (mArglist) {
1243             PyrSymbol** methargs;
1244             methargs = slotRawSymbolArray(&method->argNames)->symbols;
1245             vardef = mArglist->mVarDefs;
1246             for (i = 1; i < numArgs; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
1247                 PyrSlot* varslot;
1248                 varslot = &vardef->mVarName->mSlot;
1249                 // already declared as arg?
1250                 for (j = 0; j < i; ++j) {
1251                     if (methargs[j] == slotRawSymbol(varslot)) {
1252                         error("Argument '%s' already declared in %s:%s\n", slotRawSymbol(varslot)->name,
1253                               slotRawSymbol(&gCompilingClass->name)->name,
1254                               slotRawSymbol(&gCompilingMethod->name)->name);
1255                         nodePostErrorLine((PyrParseNode*)vardef);
1256                         compileErrors++;
1257                     }
1258                 }
1259                 // put it in arglist
1260                 methargs[i] = slotRawSymbol(varslot);
1261                 // postfl("defarg %d '%s'\n", i, slotRawSymbol(slot)->name);
1262                 /*if (slotRawSymbol(varslot)->name[0] == 'a'
1263                     && slotRawSymbol(varslot)->name[1] == 'r'
1264                     && slotRawSymbol(varslot)->name[2] == 'g')
1265                 {
1266                     post("%d  %s:%s   '%s'\n", i,
1267                         slotRawSymbol(&gCompilingClass->name)->name,
1268                         slotRawSymbol(&gCompilingMethod->name)->name,
1269                         slotRawSymbol(varslot)->name);
1270                 }*/
1271             }
1272             if (funcVarArgs) {
1273                 PyrSlot* varslot;
1274                 varslot = &mArglist->mRest->mSlot;
1275                 // already declared as arg?
1276                 for (j = 0; j < numArgs; ++j) {
1277                     if (methargs[j] == slotRawSymbol(varslot)) {
1278                         error("Argument '%s' already declared in %s:%s\n", slotRawSymbol(varslot)->name,
1279                               slotRawSymbol(&gCompilingClass->name)->name,
1280                               slotRawSymbol(&gCompilingMethod->name)->name);
1281                         nodePostErrorLine((PyrParseNode*)vardef);
1282                         compileErrors++;
1283                     }
1284                 }
1285                 // put it in arglist
1286                 methargs[i] = slotRawSymbol(varslot);
1287                 // postfl("defrest '%s'\n", slotRawSymbol(slot)->name);
1288             }
1289         }
1290         // fill prototype args
1291         if (NotNil(&method->prototypeFrame)) {
1292             SetNil(&slotRawObject(&method->prototypeFrame)->slots[0]);
1293         }
1294         if (mArglist) {
1295             vardef = mArglist->mVarDefs;
1296             for (i = 1; i < numArgs; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
1297                 PyrSlot *slot, litval;
1298                 slot = slotRawObject(&method->prototypeFrame)->slots + i;
1299                 // compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litval);
1300                 if (vardef->hasExpr(&litval))
1301                     hasVarExprs = true;
1302                 *slot = litval;
1303             }
1304             if (funcVarArgs) {
1305                 slotCopy(&slotRawObject(&method->prototypeFrame)->slots[numArgs], &o_emptyarray);
1306             }
1307         }
1308     }
1309 
1310     if (numVars) {
1311         varNames = newPyrSymbolArray(nullptr, numVars, obj_permanent | obj_immutable, false);
1312         varNames->size = numVars;
1313         SetObject(&method->varNames, varNames);
1314     } else {
1315         SetNil(&method->varNames);
1316     }
1317 
1318     // declare vars
1319     if (mVarlist) {
1320         PyrSymbol **methargs, **methvars;
1321         methargs = slotRawSymbolArray(&method->argNames)->symbols;
1322         methvars = slotRawSymbolArray(&method->varNames)->symbols;
1323         vardef = mVarlist->mVarDefs;
1324         for (i = 0; i < numVars; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
1325             PyrSlot* varslot;
1326             varslot = &vardef->mVarName->mSlot;
1327             // already declared as arg?
1328             for (j = 0; j < numArgNames; ++j) {
1329                 if (methargs[j] == slotRawSymbol(varslot)) {
1330                     error("Variable '%s' already declared in %s:%s\n", slotRawSymbol(varslot)->name,
1331                           slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name);
1332                     nodePostErrorLine((PyrParseNode*)vardef);
1333                     compileErrors++;
1334                 }
1335             }
1336             // already declared as var?
1337             for (j = 0; j < i; ++j) {
1338                 if (methvars[j] == slotRawSymbol(varslot)) {
1339                     error("Variable '%s' already declared in %s:%s\n", slotRawSymbol(varslot)->name,
1340                           slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name);
1341                     nodePostErrorLine((PyrParseNode*)vardef);
1342                     compileErrors++;
1343                 }
1344             }
1345             // put it in mVarlist
1346             methvars[i] = slotRawSymbol(varslot);
1347             // postfl("defvar %d '%s'\n", i, slotRawSymbol(slot)->name);
1348         }
1349     }
1350 
1351     if (mVarlist) {
1352         vardef = mVarlist->mVarDefs;
1353         for (i = 0; i < numVars; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
1354             PyrSlot *slot, litval;
1355             slot = slotRawObject(&method->prototypeFrame)->slots + i + numArgs + funcVarArgs;
1356             if (vardef->hasExpr(&litval))
1357                 hasVarExprs = true;
1358             // compilePyrLiteralNode(vardef->mDefVal, &litval);
1359             *slot = litval;
1360         }
1361     }
1362 
1363     methType = methNormal;
1364     if (hasVarExprs) {
1365         methType = methNormal;
1366     } else if (hasPrimitive) {
1367         methType = methPrimitive;
1368         /*
1369         if (getPrimitiveNumArgs(methraw->specialIndex) != numArgs) {
1370             post("warning: number of arguments for method %s:%s does not match primitive %s. %d vs %d\n",
1371                 slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name,
1372                 getPrimitiveName(methraw->specialIndex)->name,
1373                 numArgs, getPrimitiveNumArgs(methraw->specialIndex));
1374         }
1375         */
1376     } else if (slotRawSymbol(&gCompilingMethod->name) == s_doesNotUnderstand) {
1377         methType = methNormal;
1378     } else {
1379         int bodyType = mBody->mClassno;
1380         if (bodyType == pn_ReturnNode) {
1381             PyrReturnNode* rnode;
1382             PyrParseNode* xnode;
1383             int rtype;
1384             PyrSlot rslot;
1385 
1386             rnode = (PyrReturnNode*)mBody;
1387             xnode = (PyrParseNode*)rnode->mExpr;
1388             if (xnode) {
1389                 rtype = xnode->mClassno;
1390                 if (rtype == pn_PushLitNode) { // return literal ?
1391                     compilePyrLiteralNode((PyrLiteralNode*)xnode, &rslot);
1392                     if (IsObj(&rslot) && slotRawObject(&rslot)->classptr == class_fundef) {
1393                         methType = methNormal;
1394                     } else {
1395                         methType = methReturnLiteral;
1396                         method->selectors = rslot;
1397                     }
1398                 } else if (rtype == pn_PushNameNode) {
1399                     PyrSlot* rslot;
1400                     rslot = &((PyrPushNameNode*)xnode)->mSlot;
1401                     if (slotRawSymbol(rslot) == s_this) { // return this
1402                         methType = methReturnSelf;
1403                     } else {
1404                         if (funcFindArg((PyrBlock*)method, slotRawSymbol(rslot), &index)) { // return arg ?
1405                             // eliminate the case where its an ellipsis or keyword argument
1406                             if (index < methraw->numargs) {
1407                                 methType = methReturnArg;
1408                                 methraw->specialIndex = index; // when you change sp to sp - 1
1409                                 // methraw->specialIndex = index - 1;
1410                             }
1411                         } else if (classFindInstVar(gCompilingClass, slotRawSymbol(rslot), &index)) {
1412                             // return inst var
1413                             methType = methReturnInstVar;
1414                             methraw->specialIndex = index;
1415                         }
1416                     }
1417                 } else if (rtype == pn_CallNode) {
1418                     // need to do this for binary opcodes too..
1419                     int specialIndex;
1420                     PyrCallNode* cnode;
1421                     PyrClass* specialClass = nullptr;
1422                     cnode = (PyrCallNode*)xnode;
1423                     methType = compareCallArgs(this, cnode, &specialIndex, &specialClass);
1424                     if (methType != methNormal) {
1425                         methraw->specialIndex = specialIndex;
1426                         method->selectors = cnode->mSelector->mSlot;
1427                         if (specialClass)
1428                             method->constants = specialClass->name;
1429                     }
1430                 }
1431             } else {
1432                 methType = methReturnSelf;
1433             }
1434         } else if (bodyType == pn_AssignNode && numArgs == 2) { // assign inst var ?
1435             PyrAssignNode* anode;
1436             // post("methAssignInstVar 1  %s:%s\n",
1437             //	slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name);
1438             anode = (PyrAssignNode*)mBody;
1439             if (anode->mNext && anode->mNext->mClassno == pn_ReturnNode
1440                 && ((PyrReturnNode*)anode->mNext)->mExpr == nullptr) {
1441                 // post("methAssignInstVar 2  %s:%s\n",
1442                 //	slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name);
1443                 if (classFindInstVar(gCompilingClass, slotRawSymbol(&anode->mVarName->mSlot), &index)) {
1444                     methType = methAssignInstVar;
1445                     methraw->specialIndex = index;
1446                     // post("methAssignInstVar 3  %s:%s\n",
1447                     //	slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name);
1448                 }
1449             }
1450         }
1451     }
1452 
1453     methraw->methType = methType;
1454     // set primitive
1455     // optimize common cases
1456 
1457     if (methType == methNormal || methType == methPrimitive) {
1458         PyrSlot dummy;
1459         PyrSymbol* name;
1460 
1461         // compile body
1462         initByteCodes();
1463 
1464         if (gCompilingClass == class_int) {
1465             // handle some special cases
1466             name = slotRawSymbol(&method->name);
1467             if (name == gSpecialSelectors[opmDo]) {
1468                 compileByte(143);
1469                 compileByte(0);
1470                 compileByte(143);
1471                 compileByte(1);
1472             } else if (name == gSpecialSelectors[opmReverseDo]) {
1473                 compileByte(143);
1474                 compileByte(2);
1475                 compileByte(143);
1476                 compileByte(3);
1477                 compileByte(143);
1478                 compileByte(4);
1479             } else if (name == gSpecialSelectors[opmFor]) {
1480                 compileByte(143);
1481                 compileByte(5);
1482                 compileByte(143);
1483                 compileByte(6);
1484                 compileByte(143);
1485                 compileByte(16);
1486             } else if (name == gSpecialSelectors[opmForBy]) {
1487                 compileByte(143);
1488                 compileByte(7);
1489                 compileByte(143);
1490                 compileByte(8);
1491                 compileByte(143);
1492                 compileByte(9);
1493             } else
1494                 goto compile_body;
1495         } else if (gCompilingClass == class_arrayed_collection) {
1496             name = slotRawSymbol(&method->name);
1497             if (name == gSpecialSelectors[opmDo]) {
1498                 compileByte(143);
1499                 compileByte(10);
1500                 compileByte(143);
1501                 compileByte(1);
1502             } else if (name == gSpecialSelectors[opmReverseDo]) {
1503                 compileByte(143);
1504                 compileByte(11);
1505                 compileByte(143);
1506                 compileByte(12);
1507                 compileByte(143);
1508                 compileByte(4);
1509             } else
1510                 goto compile_body;
1511         } else if (slotRawSymbol(&gCompilingClass->name) == s_dictionary) {
1512             name = slotRawSymbol(&method->name);
1513             if (name == getsym("keysValuesArrayDo")) {
1514                 compileByte(143);
1515                 compileByte(13);
1516                 compileByte(143);
1517                 compileByte(14);
1518             } else
1519                 goto compile_body;
1520         } else if (gCompilingClass == class_number) {
1521             name = slotRawSymbol(&method->name);
1522             if (name == gSpecialSelectors[opmForSeries]) {
1523                 compileByte(143);
1524                 compileByte(29);
1525                 compileByte(143);
1526                 compileByte(30);
1527                 compileByte(143);
1528                 compileByte(31);
1529             } else
1530                 goto compile_body;
1531         } else if (gCompilingClass == class_float) {
1532             // handle some special cases
1533             name = slotRawSymbol(&method->name);
1534             if (name == gSpecialSelectors[opmDo]) {
1535                 compileByte(143);
1536                 compileByte(17);
1537                 compileByte(143);
1538                 compileByte(18);
1539             } else if (name == gSpecialSelectors[opmReverseDo]) {
1540                 compileByte(143);
1541                 compileByte(19);
1542                 compileByte(143);
1543                 compileByte(20);
1544                 compileByte(143);
1545                 compileByte(21);
1546             } else
1547                 goto compile_body;
1548         } else {
1549         compile_body:
1550             SetTailIsMethodReturn mr(false);
1551             if (mArglist) {
1552                 vardef = mArglist->mVarDefs;
1553                 for (i = 1; i < numArgs; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
1554                     vardef->compileArg(&dummy);
1555                 }
1556             }
1557             if (mVarlist) {
1558                 vardef = mVarlist->mVarDefs;
1559                 for (i = 0; i < numVars; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
1560                     vardef->compile(&dummy);
1561                 }
1562             }
1563             COMPILENODE(mBody, &dummy, true);
1564         }
1565         installByteCodes((PyrBlock*)method);
1566     }
1567 
1568     if (!oldmethod) {
1569         addMethod(gCompilingClass, method);
1570     }
1571 
1572     gCompilingMethod = nullptr;
1573     gCompilingBlock = nullptr;
1574     gPartiallyAppliedFunction = nullptr;
1575 
1576     // postfl("<-method '%s'\n", slotRawSymbol(&mMethodName->mSlot)->name);
1577 }
1578 
newPyrArgListNode(PyrVarDefNode * varDefs,PyrSlotNode * rest)1579 PyrArgListNode* newPyrArgListNode(PyrVarDefNode* varDefs, PyrSlotNode* rest) {
1580     PyrArgListNode* node = ALLOCNODE(PyrArgListNode);
1581     node->mVarDefs = varDefs;
1582     node->mRest = rest;
1583     return node;
1584 }
1585 
compile(PyrSlot * result)1586 void PyrArgListNode::compile(PyrSlot* result) {
1587     error("compilePyrArgListNode: shouldn't get here.\n");
1588     compileErrors++;
1589 }
1590 
1591 
newPyrVarListNode(PyrVarDefNode * vardefs,int flags)1592 PyrVarListNode* newPyrVarListNode(PyrVarDefNode* vardefs, int flags) {
1593     PyrVarListNode* node = ALLOCNODE(PyrVarListNode);
1594     node->mVarDefs = vardefs;
1595     node->mFlags = flags;
1596     return node;
1597 }
1598 
compile(PyrSlot * result)1599 void PyrVarListNode::compile(PyrSlot* result) {
1600     error("compilePyrVarListNode: shouldn't get here.\n");
1601     compileErrors++;
1602 }
1603 
newPyrVarDefNode(PyrSlotNode * varName,PyrParseNode * defVal,int flags)1604 PyrVarDefNode* newPyrVarDefNode(PyrSlotNode* varName, PyrParseNode* defVal, int flags) {
1605     PyrVarDefNode* node = ALLOCNODE(PyrVarDefNode);
1606     node->mVarName = varName;
1607     node->mDefVal = defVal;
1608     node->mFlags = flags;
1609     node->mDrop = true;
1610     return node;
1611 }
1612 
hasExpr(PyrSlot * result)1613 bool PyrVarDefNode::hasExpr(PyrSlot* result) {
1614     if (result)
1615         SetNil(result);
1616     if (!mDefVal)
1617         return false;
1618     if (mDefVal->mClassno != pn_PushLitNode && mDefVal->mClassno != pn_LiteralNode) {
1619         // post("hasExpr A %s:%s %s %d\n", slotRawSymbol(&gCompilingClass->name)->name,
1620         // slotRawSymbol(&gCompilingMethod->name)->name, mVarName->slotRawSymbol(&mSlot)->name, mDefVal->mClassno);
1621         return true;
1622     }
1623     PyrPushLitNode* node = (PyrPushLitNode*)mDefVal;
1624 
1625     if (IsPtr(&node->mSlot)) {
1626         PyrParseNode* litnode = (PyrParseNode*)slotRawPtr(&node->mSlot);
1627         if (litnode) {
1628             if (litnode->mClassno == pn_BlockNode) {
1629                 // post("hasExpr B %s:%s %s %d\n", slotRawSymbol(&gCompilingClass->name)->name,
1630                 // slotRawSymbol(&gCompilingMethod->name)->name, mVarName->slotRawSymbol(&mSlot)->name, node->mClassno);
1631                 return true;
1632             } else {
1633                 if (result)
1634                     node->compileLiteral(result);
1635             }
1636         }
1637     } else if (result)
1638         *result = node->mSlot;
1639     if (node->mParens)
1640         return true;
1641     return false;
1642 }
1643 
compile(PyrSlot * result)1644 void PyrVarDefNode::compile(PyrSlot* result) {
1645     if (hasExpr(nullptr)) {
1646         COMPILENODE(mDefVal, result, false);
1647         compileAssignVar((PyrParseNode*)this, slotRawSymbol(&mVarName->mSlot), mDrop);
1648     }
1649 
1650     // error("compilePyrVarDefNode: shouldn't get here.\n");
1651     // compileErrors++;
1652 }
1653 
compileArg(PyrSlot * result)1654 void PyrVarDefNode::compileArg(PyrSlot* result) {
1655     if (hasExpr(nullptr)) {
1656         ByteCodes trueByteCodes;
1657 
1658         compilePushVar((PyrParseNode*)this, slotRawSymbol(&mVarName->mSlot));
1659 
1660         mDrop = false;
1661         trueByteCodes = compileBodyWithGoto(this, 0, true);
1662         int jumplen = byteCodeLength(trueByteCodes);
1663 
1664         compileByte(143); // special opcodes
1665         compileByte(26);
1666         compileByte((jumplen >> 8) & 0xFF);
1667         compileByte(jumplen & 0xFF);
1668         compileAndFreeByteCodes(trueByteCodes);
1669         compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean
1670     }
1671 
1672     // error("compilePyrVarDefNode: shouldn't get here.\n");
1673     // compileErrors++;
1674 }
1675 
1676 
newPyrCallNode(PyrSlotNode * selector,PyrParseNode * arglist,PyrParseNode * keyarglist,PyrParseNode * blocklist)1677 PyrCallNode* newPyrCallNode(PyrSlotNode* selector, PyrParseNode* arglist, PyrParseNode* keyarglist,
1678                             PyrParseNode* blocklist) {
1679     PyrCallNode* node = ALLOCNODE(PyrCallNode);
1680     node->mSelector = selector;
1681 
1682     arglist = linkNextNode(arglist, blocklist);
1683 
1684     node->mArglist = arglist;
1685     node->mKeyarglist = keyarglist;
1686     return node;
1687 }
1688 
isPartialApplication()1689 int PyrCallNode::isPartialApplication() {
1690     int sum = 0;
1691     PyrParseNode* argnode = mArglist;
1692     for (; argnode; argnode = argnode->mNext) {
1693         if (argnode->mClassno == pn_CurryArgNode) {
1694             ((PyrCurryArgNode*)argnode)->mArgNum = sum;
1695             sum++;
1696         }
1697     }
1698 
1699     PyrParseNode* keynode = mKeyarglist;
1700     for (; keynode; keynode = keynode->mNext) {
1701         if (keynode->mClassno == pn_CurryArgNode) {
1702             ((PyrCurryArgNode*)keynode)->mArgNum = sum;
1703             sum++;
1704         }
1705     }
1706     return sum;
1707 }
1708 
compilePartialApplication(int numCurryArgs,PyrSlot * result)1709 void PyrCallNodeBase::compilePartialApplication(int numCurryArgs, PyrSlot* result) {
1710     // create a function
1711     // compile the call
1712 
1713     ByteCodes savedBytes = saveByteCodeArray();
1714 
1715     int flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
1716     PyrBlock* block = newPyrBlock(flags);
1717 
1718     PyrSlot blockSlot;
1719     SetObject(&blockSlot, block);
1720 
1721     int prevFunctionHighestExternalRef = gFunctionHighestExternalRef;
1722     bool prevFunctionCantBeClosed = gFunctionCantBeClosed;
1723     gFunctionHighestExternalRef = 0;
1724     gFunctionCantBeClosed = false;
1725 
1726     PyrClass* prevClass = gCompilingClass;
1727     PyrBlock* prevBlock = gCompilingBlock;
1728     gCompilingBlock = block;
1729 
1730     PyrBlock* prevPartiallyAppliedFunction = gPartiallyAppliedFunction;
1731     gPartiallyAppliedFunction = block;
1732 
1733     PyrMethodRaw* methraw = METHRAW(block);
1734     methraw->unused1 = 0;
1735     methraw->unused2 = 0;
1736 
1737     methraw->needsHeapContext = 0;
1738 
1739     SetObject(&block->contextDef, prevBlock);
1740     ////
1741     methraw->varargs = 0;
1742 
1743     methraw->frameSize = (numCurryArgs + FRAMESIZE) * sizeof(PyrSlot);
1744     PyrObject* proto = newPyrArray(compileGC(), numCurryArgs, flags, false);
1745     proto->size = numCurryArgs;
1746     SetObject(&block->prototypeFrame, proto);
1747 
1748     PyrSymbolArray* argNames = newPyrSymbolArray(compileGC(), numCurryArgs, flags, false);
1749     argNames->size = numCurryArgs;
1750     SetObject(&block->argNames, argNames);
1751 
1752     SetNil(&block->varNames);
1753 
1754     methraw->numargs = numCurryArgs;
1755     methraw->numvars = 0;
1756     methraw->posargs = numCurryArgs;
1757     methraw->numtemps = numCurryArgs;
1758     methraw->popSize = numCurryArgs;
1759     methraw->methType = methBlock;
1760 
1761     {
1762         PyrSymbol* s_empty = getsym("_");
1763         PyrSymbol** blockargs = slotRawSymbolArray(&block->argNames)->symbols;
1764         for (int i = 0; i < numCurryArgs; ++i) {
1765             // put it in mArglist
1766             blockargs[i] = s_empty;
1767             SetNil(proto->slots + i);
1768         }
1769     }
1770 
1771     initByteCodes();
1772     {
1773         SetTailBranch branch(true);
1774         SetTailIsMethodReturn mr(false);
1775         PyrSlot body;
1776         compileCall(&body);
1777     }
1778     compileOpcode(opSpecialOpcode, opcFunctionReturn);
1779     installByteCodes(block);
1780 
1781     gCompilingBlock = prevBlock;
1782     gPartiallyAppliedFunction = prevPartiallyAppliedFunction;
1783 
1784     restoreByteCodeArray(savedBytes);
1785     int index = conjureLiteralSlotIndex(this, gCompilingBlock, &blockSlot);
1786     compileOpcode(opExtended, opPushLiteral);
1787     compileByte(index);
1788 
1789     if (!gFunctionCantBeClosed && gFunctionHighestExternalRef == 0) {
1790         SetNil(&block->contextDef);
1791     } else {
1792         METHRAW(prevBlock)->needsHeapContext = 1;
1793     }
1794 
1795     gCompilingBlock = prevBlock;
1796     gCompilingClass = prevClass;
1797     gPartiallyAppliedFunction = prevPartiallyAppliedFunction;
1798     gFunctionCantBeClosed = gFunctionCantBeClosed || prevFunctionCantBeClosed;
1799     gFunctionHighestExternalRef = sc_max(gFunctionHighestExternalRef - 1, prevFunctionHighestExternalRef);
1800 }
1801 
compile(PyrSlot * result)1802 void PyrCallNodeBase::compile(PyrSlot* result) {
1803     int numCurryArgs = isPartialApplication();
1804     if (numCurryArgs) {
1805         compilePartialApplication(numCurryArgs, result);
1806     } else {
1807         compileCall(result);
1808     }
1809 }
1810 
isSeries(PyrParseNode * node,PyrParseNode ** args)1811 bool isSeries(PyrParseNode* node, PyrParseNode** args) {
1812     if (node->mClassno != pn_CallNode)
1813         return false;
1814     PyrCallNode* callnode = (PyrCallNode*)node;
1815     if (slotRawSymbol(&callnode->mSelector->mSlot) != s_series)
1816         return false;
1817     if (callnode->mKeyarglist)
1818         return false;
1819     *args = callnode->mArglist;
1820     return true;
1821 }
1822 
compileCall(PyrSlot * result)1823 void PyrCallNode::compileCall(PyrSlot* result) {
1824     int index, selType;
1825     PyrSlot dummy;
1826     bool varFound;
1827     PyrParseNode* argnode2;
1828 
1829     // postfl("compilePyrCallNode\n");
1830     PyrParseNode* argnode = mArglist;
1831     PyrParseNode* keynode = mKeyarglist;
1832     int numArgs = nodeListLength(argnode);
1833     int numKeyArgs = nodeListLength(keynode);
1834     int isSuper = isSuperObjNode(argnode);
1835     int numBlockArgs = METHRAW(gCompilingBlock)->numargs;
1836 
1837     slotRawSymbol(&mSelector->mSlot)->flags |= sym_Called;
1838     index = conjureSelectorIndex((PyrParseNode*)mSelector, gCompilingBlock, isSuper, slotRawSymbol(&mSelector->mSlot),
1839                                  &selType);
1840 
1841     if (numKeyArgs > 0 || (numArgs > 15 && !(selType == selSwitch || selType == selCase))) {
1842         for (; argnode; argnode = argnode->mNext) {
1843             COMPILENODE(argnode, &dummy, false);
1844         }
1845         for (; keynode; keynode = keynode->mNext) {
1846             COMPILENODE(keynode, &dummy, false);
1847         }
1848         if (isSuper) {
1849             compileTail();
1850             compileByte(opSendSuper);
1851             compileByte(numArgs + 2 * numKeyArgs);
1852             compileByte(numKeyArgs);
1853             compileByte(index);
1854         } else {
1855             switch (selType) {
1856             case selNormal:
1857                 compileTail();
1858                 compileByte(opSendMsg);
1859                 compileByte(numArgs + 2 * numKeyArgs);
1860                 compileByte(numKeyArgs);
1861                 compileByte(index);
1862                 break;
1863             case selSpecial:
1864                 compileTail();
1865                 compileByte(opSendSpecialMsg);
1866                 compileByte(numArgs + 2 * numKeyArgs);
1867                 compileByte(numKeyArgs);
1868                 compileByte(index);
1869                 break;
1870             case selUnary:
1871             case selBinary:
1872                 index = conjureLiteralSlotIndex((PyrParseNode*)mSelector, gCompilingBlock, &mSelector->mSlot);
1873                 // fall through
1874             default:
1875                 compileTail();
1876                 compileByte(opSendMsg);
1877                 compileByte(numArgs + 2 * numKeyArgs);
1878                 compileByte(numKeyArgs);
1879                 compileByte(index);
1880                 break;
1881             }
1882         }
1883     } else if (isSuper) {
1884         if (numArgs == 1) {
1885             // pushes this as well, don't compile arg
1886             gFunctionCantBeClosed = true;
1887             compileTail();
1888             compileOpcode(opSendSuper, numArgs);
1889             compileByte(index);
1890         } else {
1891             for (; argnode; argnode = argnode->mNext) {
1892                 COMPILENODE(argnode, &dummy, false);
1893             }
1894             compileTail();
1895             compileOpcode(opSendSuper, numArgs);
1896             compileByte(index);
1897         }
1898     } else {
1899         PyrSymbol* varname;
1900         if (argnode->mClassno == pn_PushNameNode) {
1901             varname = slotRawSymbol(&((PyrPushNameNode*)argnode)->mSlot);
1902         } else {
1903             varname = nullptr;
1904         }
1905         if (varname == s_this) {
1906             gFunctionCantBeClosed = true;
1907         }
1908         switch (selType) {
1909         case selNormal:
1910             if (numArgs == 1 && varname == s_this) {
1911                 compileTail();
1912                 compileOpcode(opSendMsg, 0);
1913                 compileByte(index);
1914                 //} else if (numArgs>1 && numArgs == numBlockArgs) {
1915             } else if (numArgs > 1 && numArgs == numBlockArgs) {
1916                 // try for multiple push optimization
1917                 int code;
1918                 code = checkPushAllArgs(argnode, numArgs);
1919                 if (code == push_Normal)
1920                     goto normal;
1921                 else if (code == push_AllArgs) {
1922                     compileTail();
1923                     compileByte(137); // push all args, send msg
1924                     compileByte(index);
1925                     // post("137 pushAllArgs     %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name,
1926                     //	slotRawSymbol(&gCompilingMethod->name)->name);
1927                 } else if (code == push_AllButFirstArg) {
1928                     COMPILENODE(argnode, &dummy, false);
1929                     compileTail();
1930                     compileByte(138); // push all but first arg, send msg
1931                     compileByte(index);
1932                     // post("138 pushAllButFirstArg     %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name,
1933                     //	slotRawSymbol(&gCompilingMethod->name)->name);
1934                 } else
1935                     goto normal;
1936             } else if (numArgs > 2 && numArgs == numBlockArgs + 1) {
1937                 int code;
1938                 code = checkPushAllButFirstTwoArgs(argnode, numBlockArgs);
1939                 if (code == push_Normal)
1940                     goto normal;
1941                 else if (code == push_AllButFirstArg2) {
1942                     COMPILENODE(argnode, &dummy, false);
1943                     COMPILENODE(argnode->mNext, &dummy, false);
1944                     compileTail();
1945                     compileByte(141); // one arg pushed, push all but first arg, send msg
1946                     compileByte(index);
1947                     // post("141 pushAllButFirstArg2    %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name,
1948                     //	slotRawSymbol(&gCompilingMethod->name)->name);
1949                 } else
1950                     goto normal;
1951 
1952             } else {
1953             normal:
1954                 for (; argnode; argnode = argnode->mNext) {
1955                     COMPILENODE(argnode, &dummy, false);
1956                 }
1957                 compileTail();
1958                 compileOpcode(opSendMsg, numArgs);
1959                 compileByte(index);
1960             }
1961             break;
1962         case selSpecial:
1963             if (numArgs == 1) {
1964                 if (varname == s_this) {
1965                     compileTail();
1966                     compileOpcode(opSendSpecialMsg, 0);
1967                     compileByte(index);
1968                 } else if (varname) {
1969                     PyrClass* classobj;
1970                     PyrBlock* tempFunc;
1971                     int varType, varLevel, varIndex;
1972                     classobj = gCompilingClass;
1973                     varFound =
1974                         findVarName(gCompilingBlock, &classobj, varname, &varType, &varLevel, &varIndex, &tempFunc);
1975                     if (varFound && varType == varInst) {
1976                         // post("136 pushInstVar(sp) %s:%s '%s' %d %d\n", slotRawSymbol(&gCompilingClass->name)->name,
1977                         //	slotRawSymbol(&gCompilingMethod->name)->name, varname->name, varIndex, index);
1978                         compileTail();
1979                         compileByte(136);
1980                         compileByte(varIndex);
1981                         compileByte(index);
1982                     } else
1983                         goto special;
1984                 } else
1985                     goto special;
1986             } else if (index == opmDo && isSeries(argnode, &argnode)) {
1987                 index = opmForSeries;
1988                 mArglist = linkNextNode(argnode, mArglist->mNext);
1989                 numArgs = nodeListLength(mArglist);
1990                 goto special;
1991             } else if (numArgs > 1 && numArgs == numBlockArgs) {
1992                 //} else if (numArgs>1 && numArgs == numBlockArgs) {
1993                 // try for multiple push optimization
1994                 int code;
1995                 code = checkPushAllArgs(argnode, numArgs);
1996                 if (code == push_Normal)
1997                     goto special;
1998                 else if (code == push_AllArgs) {
1999                     compileTail();
2000                     compileByte(139); // push all args, send special msg
2001                     compileByte(index);
2002                     // post("139 pushAllArgs(sp) %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name,
2003                     //	slotRawSymbol(&gCompilingMethod->name)->name);
2004                 } else if (code == push_AllButFirstArg) {
2005                     COMPILENODE(argnode, &dummy, false);
2006                     compileTail();
2007                     compileByte(140); // push all but first arg, send special msg
2008                     compileByte(index);
2009                     // post("140 pushAllButFirstArg(sp) %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name,
2010                     //	slotRawSymbol(&gCompilingMethod->name)->name);
2011                 } else
2012                     goto special;
2013             } else if (numArgs > 2 && numArgs == numBlockArgs + 1) {
2014                 int code;
2015                 code = checkPushAllButFirstTwoArgs(argnode, numBlockArgs);
2016                 if (code == push_Normal)
2017                     goto special;
2018                 else if (code == push_AllButFirstArg2) {
2019                     COMPILENODE(argnode, &dummy, false);
2020                     COMPILENODE(argnode->mNext, &dummy, false);
2021                     compileTail();
2022                     compileByte(142); // one arg pushed, push all but first arg, send msg
2023                     compileByte(index);
2024                     // post("142 pushAllButFirstArg2(sp)    %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name,
2025                     //	slotRawSymbol(&gCompilingMethod->name)->name);
2026                 } else
2027                     goto special;
2028             } else {
2029                 int i;
2030             special:
2031                 for (i = 0; argnode; argnode = argnode->mNext, i++) {
2032                     COMPILENODE(argnode, &dummy, false);
2033                 }
2034                 compileTail();
2035                 compileOpcode(opSendSpecialMsg, numArgs);
2036                 compileByte(index);
2037             }
2038             break;
2039         case selUnary:
2040             if (numArgs != 1) {
2041                 index = conjureLiteralSlotIndex((PyrParseNode*)mSelector, gCompilingBlock, &mSelector->mSlot);
2042                 goto defaultCase;
2043             }
2044             for (; argnode; argnode = argnode->mNext) {
2045                 COMPILENODE(argnode, &dummy, false);
2046             }
2047             compileTail();
2048             compileOpcode(opSendSpecialUnaryArithMsg, index);
2049             break;
2050         case selBinary:
2051             if (numArgs != 2) {
2052                 index = conjureLiteralSlotIndex((PyrParseNode*)mSelector, gCompilingBlock, &mSelector->mSlot);
2053                 goto defaultCase;
2054             }
2055             // for (; argnode; argnode = argnode->mNext) {
2056             //	COMPILENODE(argnode, &dummy, false);
2057             //}
2058             argnode2 = argnode->mNext;
2059             if (index == opAdd && argnode2->mClassno == pn_PushLitNode && IsInt(&((PyrPushLitNode*)argnode2)->mSlot)
2060                 && slotRawInt(&((PyrPushLitNode*)argnode2)->mSlot) == 1) {
2061                 COMPILENODE(argnode, &dummy, false);
2062                 compileOpcode(opPushSpecialValue, opsvPlusOne);
2063             } else if (index == opSub && argnode2->mClassno == pn_PushLitNode
2064                        && IsInt(&((PyrPushLitNode*)argnode2)->mSlot)
2065                        && slotRawInt(&((PyrPushLitNode*)argnode2)->mSlot) == 1) {
2066                 COMPILENODE(argnode, &dummy, false);
2067                 compileOpcode(opPushSpecialValue, opsvMinusOne);
2068             } else {
2069                 COMPILENODE(argnode, &dummy, false);
2070                 COMPILENODE(argnode->mNext, &dummy, false);
2071                 compileTail();
2072                 compileOpcode(opSendSpecialBinaryArithMsg, index);
2073             }
2074             break;
2075         case selIf:
2076             compileAnyIfMsg(this);
2077             break;
2078         case selCase:
2079             compileCaseMsg(this);
2080             break;
2081         case selSwitch:
2082             compileSwitchMsg(this);
2083             break;
2084         case selWhile:
2085             compileWhileMsg(this);
2086             break;
2087         case selLoop:
2088             compileLoopMsg(this);
2089             break;
2090         case selAnd:
2091             if (numArgs == 2)
2092                 compileAndMsg(argnode, argnode->mNext);
2093             else
2094                 goto special;
2095             break;
2096         case selOr:
2097             if (numArgs == 2)
2098                 compileOrMsg(argnode, argnode->mNext);
2099             else
2100                 goto special;
2101             break;
2102         case selQuestionMark:
2103             if (numArgs == 2)
2104                 compileQMsg(argnode, argnode->mNext);
2105             break;
2106         case selDoubleQuestionMark:
2107             if (numArgs == 2)
2108                 compileQQMsg(argnode, argnode->mNext);
2109             break;
2110         case selExclamationQuestionMark:
2111             if (numArgs == 2)
2112                 compileXQMsg(argnode, argnode->mNext);
2113             break;
2114         default:
2115         defaultCase:
2116             if (numArgs == 1 && varname == s_this) {
2117                 compileTail();
2118                 compileOpcode(opSendMsg, 0);
2119                 compileByte(index);
2120             } else {
2121                 for (; argnode; argnode = argnode->mNext) {
2122                     COMPILENODE(argnode, &dummy, false);
2123                 }
2124                 compileTail();
2125                 compileOpcode(opSendMsg, numArgs);
2126                 compileByte(index);
2127             }
2128             break;
2129         }
2130     }
2131 }
2132 
compileSubExpression(PyrPushLitNode * litnode,bool onTailBranch)2133 ByteCodes compileSubExpression(PyrPushLitNode* litnode, bool onTailBranch) {
2134     return compileSubExpressionWithGoto(litnode, 0, onTailBranch);
2135 }
2136 
compileSubExpressionWithGoto(PyrPushLitNode * litnode,int branchLen,bool onTailBranch)2137 ByteCodes compileSubExpressionWithGoto(PyrPushLitNode* litnode, int branchLen, bool onTailBranch) {
2138     PyrBlockNode* bnode = (PyrBlockNode*)slotRawPtr(&litnode->mSlot);
2139     return compileBodyWithGoto(bnode->mBody, branchLen, onTailBranch);
2140 }
2141 
compileBodyWithGoto(PyrParseNode * body,int branchLen,bool onTailBranch)2142 ByteCodes compileBodyWithGoto(PyrParseNode* body, int branchLen, bool onTailBranch) {
2143     ByteCodes currentByteCodes, subExprByteCodes;
2144     PyrSlot dummy;
2145 
2146     PyrBlock* prevPartiallyAppliedFunction = gPartiallyAppliedFunction;
2147     gPartiallyAppliedFunction = nullptr;
2148 
2149     currentByteCodes = saveByteCodeArray();
2150 
2151     COMPILENODE(body, &dummy, onTailBranch);
2152     if (branchLen) {
2153         if (!byteCodeLength(gCompilingByteCodes)) {
2154             compileOpcode(opPushSpecialValue, opsvNil); // push nil
2155         }
2156         compileJump(opcJumpFwd, branchLen);
2157     }
2158 
2159     subExprByteCodes = getByteCodes();
2160     restoreByteCodeArray(currentByteCodes);
2161 
2162     gPartiallyAppliedFunction = prevPartiallyAppliedFunction;
2163 
2164     return subExprByteCodes;
2165 }
2166 
2167 #if 0
2168 ByteCodes compileDefaultValue(int litIndex, int realExprLen)
2169 {
2170   ByteCodes	currentByteCodes, defaultByteCodes;
2171 
2172   currentByteCodes = saveByteCodeArray();
2173 
2174   compileOpcode(opPushSpecialValue, litIndex);
2175   compileJump(realExprLen, unconditionalJump);
2176 
2177   defaultByteCodes = getByteCodes();
2178   restoreByteCodeArray(currentByteCodes);
2179 
2180   return (defaultByteCodes);
2181 }
2182 #endif
2183 
isAnInlineableBlock(PyrParseNode * node)2184 bool isAnInlineableBlock(PyrParseNode* node) {
2185     bool res = false;
2186     if (node->mClassno == pn_PushLitNode) {
2187         PyrPushLitNode* anode;
2188         PyrBlockNode* bnode;
2189         anode = (PyrPushLitNode*)node;
2190         if (IsPtr(&anode->mSlot) && (bnode = (PyrBlockNode*)(slotRawPtr(&anode->mSlot)))->mClassno == pn_BlockNode) {
2191             if (bnode->mArglist || bnode->mVarlist) {
2192                 if (SC_LanguageConfig::getPostInlineWarnings()) {
2193                     post("WARNING: FunctionDef contains variable declarations and so"
2194                          " will not be inlined.\n");
2195                     if (bnode->mArglist)
2196                         nodePostErrorLine((PyrParseNode*)bnode->mArglist);
2197                     else
2198                         nodePostErrorLine((PyrParseNode*)bnode->mVarlist);
2199                 }
2200             } else
2201                 res = true;
2202         }
2203     }
2204     return res;
2205 }
2206 
isAnInlineableAtomicLiteralBlock(PyrParseNode * node)2207 bool isAnInlineableAtomicLiteralBlock(PyrParseNode* node) {
2208     bool res = false;
2209     if (node->mClassno == pn_PushLitNode) {
2210         PyrPushLitNode* anode;
2211         PyrBlockNode* bnode;
2212         anode = (PyrPushLitNode*)node;
2213         if (IsPtr(&anode->mSlot) && (bnode = (PyrBlockNode*)(slotRawPtr(&anode->mSlot)))->mClassno == pn_BlockNode) {
2214             if (bnode->mArglist || bnode->mVarlist) {
2215                 if (SC_LanguageConfig::getPostInlineWarnings()) {
2216                     post("WARNING: FunctionDef contains variable declarations and so"
2217                          " will not be inlined.\n");
2218                     if (bnode->mArglist)
2219                         nodePostErrorLine((PyrParseNode*)bnode->mArglist);
2220                     else
2221                         nodePostErrorLine((PyrParseNode*)bnode->mVarlist);
2222                 }
2223             } else {
2224                 if (bnode->mBody->mClassno == pn_DropNode
2225                     && ((PyrDropNode*)bnode->mBody)->mExpr2->mClassno == pn_BlockReturnNode)
2226                     res = isAtomicLiteral(((PyrDropNode*)bnode->mBody)->mExpr1);
2227                 else
2228                     res = false;
2229             }
2230         }
2231     }
2232     return res;
2233 }
2234 
isAtomicLiteral(PyrParseNode * node)2235 bool isAtomicLiteral(PyrParseNode* node) {
2236     bool res = false;
2237     if (node->mClassno == pn_PushLitNode) {
2238         PyrPushLitNode* anode;
2239         anode = (PyrPushLitNode*)node;
2240         if (NotObj(&anode->mSlot) && !IsPtr(&anode->mSlot))
2241             res = true;
2242     }
2243     return res;
2244 }
2245 
isWhileTrue(PyrParseNode * node)2246 bool isWhileTrue(PyrParseNode* node) {
2247     bool res = false;
2248     if (node->mClassno == pn_PushLitNode) {
2249         PyrPushLitNode* anode;
2250         PyrBlockNode* bnode;
2251         anode = (PyrPushLitNode*)node;
2252         if (IsPtr(&anode->mSlot) && (bnode = (PyrBlockNode*)(slotRawPtr(&anode->mSlot)))->mClassno == pn_BlockNode) {
2253             if (bnode->mArglist || bnode->mVarlist) {
2254                 /*
2255                 post("WARNING: FunctionDef contains variable declarations and so"
2256                     " will not be inlined.\n");
2257                 if (bnode->mArglist) nodePostErrorLine((PyrParseNode*)bnode->mArglist);
2258                 else nodePostErrorLine((PyrParseNode*)bnode->mVarlist);
2259                 */
2260             } else {
2261                 if (bnode->mBody->mClassno == pn_PushLitNode && IsTrue(&((PyrPushLitNode*)bnode->mBody)->mSlot)) {
2262                     res = true;
2263                 }
2264             }
2265         } else if (IsTrue(&anode->mSlot)) {
2266             res = true;
2267         }
2268     }
2269     return res;
2270 }
2271 
compileAndMsg(PyrParseNode * arg1,PyrParseNode * arg2)2272 void compileAndMsg(PyrParseNode* arg1, PyrParseNode* arg2) {
2273     PyrSlot dummy;
2274     ByteCodes trueByteCodes;
2275 
2276     COMPILENODE(arg1, &dummy, false);
2277     if (isAnInlineableBlock(arg2)) {
2278         trueByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true);
2279 
2280         compileJump(opcJumpIfFalsePushFalse, byteCodeLength(trueByteCodes));
2281         compileAndFreeByteCodes(trueByteCodes);
2282     } else {
2283         COMPILENODE(arg2, &dummy, false);
2284         compileTail();
2285         compileOpcode(opSendSpecialMsg, 2);
2286         compileByte(opmAnd);
2287     }
2288 }
2289 
compileOrMsg(PyrParseNode * arg1,PyrParseNode * arg2)2290 void compileOrMsg(PyrParseNode* arg1, PyrParseNode* arg2) {
2291     PyrSlot dummy;
2292     ByteCodes falseByteCodes;
2293 
2294     COMPILENODE(arg1, &dummy, false);
2295     if (isAnInlineableBlock(arg2)) {
2296         falseByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true);
2297 
2298         compileJump(opcJumpIfTruePushTrue, byteCodeLength(falseByteCodes));
2299         compileAndFreeByteCodes(falseByteCodes);
2300     } else {
2301         COMPILENODE(arg2, &dummy, false);
2302         compileTail();
2303         compileOpcode(opSendSpecialMsg, 2);
2304         compileByte(opmOr);
2305     }
2306 }
2307 
compileQMsg(PyrParseNode * arg1,PyrParseNode * arg2)2308 void compileQMsg(PyrParseNode* arg1, PyrParseNode* arg2) {
2309     // question mark.
2310     PyrSlot dummy;
2311 
2312     COMPILENODE(arg1, &dummy, false);
2313     COMPILENODE(arg2, &dummy, false);
2314     compileByte(143); // special opcodes
2315     compileByte(22); // ??
2316 }
2317 
compileQQMsg(PyrParseNode * arg1,PyrParseNode * arg2)2318 void compileQQMsg(PyrParseNode* arg1, PyrParseNode* arg2) {
2319     // double question mark. ?? {|obj| ^if (this.notNil, this, func) }
2320     PyrSlot dummy;
2321 
2322     COMPILENODE(arg1, &dummy, false);
2323     if (isAnInlineableBlock(arg2)) {
2324         ByteCodes nilByteCodes;
2325         nilByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true);
2326 
2327         int jumplen = byteCodeLength(nilByteCodes);
2328         compileByte(143); // special opcodes
2329         compileByte(23); // ??
2330         compileByte((jumplen >> 8) & 0xFF);
2331         compileByte(jumplen & 0xFF);
2332         compileAndFreeByteCodes(nilByteCodes);
2333     } else {
2334         COMPILENODE(arg2, &dummy, false);
2335         compileTail();
2336         compileOpcode(opSendSpecialMsg, 2);
2337         compileByte(opmDoubleQuestionMark);
2338     }
2339 }
2340 
compileXQMsg(PyrParseNode * arg1,PyrParseNode * arg2)2341 void compileXQMsg(PyrParseNode* arg1, PyrParseNode* arg2) {
2342     // double question mark. !? {|obj| ^if (this.isNil, this, func) }
2343     PyrSlot dummy;
2344 
2345     COMPILENODE(arg1, &dummy, false);
2346     if (isAnInlineableBlock(arg2)) {
2347         ByteCodes nilByteCodes;
2348         nilByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true);
2349 
2350         int jumplen = byteCodeLength(nilByteCodes);
2351         compileByte(143); // special opcodes
2352         compileByte(27); // !?
2353         compileByte((jumplen >> 8) & 0xFF);
2354         compileByte(jumplen & 0xFF);
2355         compileAndFreeByteCodes(nilByteCodes);
2356     } else {
2357         COMPILENODE(arg2, &dummy, false);
2358         compileTail();
2359         compileOpcode(opSendSpecialMsg, 2);
2360         compileByte(opmExclamationQuestionMark);
2361     }
2362 }
2363 
compileAnyIfMsg(PyrCallNodeBase2 * node)2364 void compileAnyIfMsg(PyrCallNodeBase2* node) {
2365     PyrParseNode* arg1 = node->mArglist;
2366 
2367     if (arg1->mClassno == pn_CallNode) {
2368         PyrCallNode* callNode = (PyrCallNode*)arg1;
2369         int numCallArgs = nodeListLength(callNode->mArglist);
2370         int numCallKeyArgs = nodeListLength(callNode->mKeyarglist);
2371         if (numCallArgs == 1 && numCallKeyArgs == 0) {
2372             if (slotRawSymbol(&callNode->mSelector->mSlot) == gSpecialUnarySelectors[opIsNil]) {
2373                 compileIfNilMsg(node, true);
2374                 return;
2375             } else if (slotRawSymbol(&callNode->mSelector->mSlot) == gSpecialUnarySelectors[opNotNil]) {
2376                 compileIfNilMsg(node, false);
2377                 return;
2378             }
2379         }
2380     }
2381     compileIfMsg(node);
2382 }
2383 
compileIfMsg(PyrCallNodeBase2 * node)2384 void compileIfMsg(PyrCallNodeBase2* node) {
2385     PyrSlot dummy;
2386     ByteCodes trueByteCodes, falseByteCodes;
2387 
2388     int numArgs = nodeListLength(node->mArglist);
2389     PyrParseNode* arg1 = node->mArglist;
2390     PyrParseNode *arg2, *arg3;
2391 
2392     if (numArgs == 2) {
2393         arg2 = arg1->mNext;
2394 
2395         if (isAnInlineableBlock(arg2)) {
2396             COMPILENODE(arg1, &dummy, false);
2397 
2398             trueByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true);
2399             if (byteCodeLength(trueByteCodes)) {
2400                 compileJump(opcJumpIfFalsePushNil, byteCodeLength(trueByteCodes));
2401                 compileAndFreeByteCodes(trueByteCodes);
2402             } else {
2403                 compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean
2404                 compileOpcode(opPushSpecialValue, opsvNil); // push nil
2405             }
2406         } else
2407             goto unoptimized;
2408     } else if (numArgs == 3) {
2409         arg2 = arg1->mNext;
2410         arg3 = arg2->mNext;
2411         if (isAnInlineableBlock(arg2) && isAnInlineableBlock(arg3)) {
2412             COMPILENODE(arg1, &dummy, false);
2413             falseByteCodes = compileSubExpression((PyrPushLitNode*)arg3, true);
2414             trueByteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)arg2, byteCodeLength(falseByteCodes), true);
2415             if (byteCodeLength(falseByteCodes)) {
2416                 compileJump(opcJumpIfFalse, byteCodeLength(trueByteCodes));
2417                 compileAndFreeByteCodes(trueByteCodes);
2418                 compileAndFreeByteCodes(falseByteCodes);
2419             } else if (byteCodeLength(trueByteCodes)) {
2420                 compileJump(opcJumpIfFalsePushNil, byteCodeLength(trueByteCodes));
2421                 compileAndFreeByteCodes(trueByteCodes);
2422             } else {
2423                 compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean
2424                 compileOpcode(opPushSpecialValue, opsvNil); // push nil
2425             }
2426         } else
2427             goto unoptimized;
2428     } else {
2429     unoptimized:
2430         for (; arg1; arg1 = arg1->mNext) {
2431             COMPILENODE(arg1, &dummy, false);
2432         }
2433         compileTail();
2434         compileOpcode(opSendSpecialMsg, numArgs);
2435         compileByte(opmIf);
2436     }
2437 }
2438 
compileIfNilMsg(PyrCallNodeBase2 * node,bool flag)2439 void compileIfNilMsg(PyrCallNodeBase2* node, bool flag) {
2440     PyrSlot dummy;
2441     ByteCodes trueByteCodes, falseByteCodes;
2442     PyrParseNode *arg2, *arg3;
2443 
2444     int numArgs = nodeListLength(node->mArglist);
2445     PyrParseNode* arg1 = node->mArglist;
2446 
2447     if (numArgs < 2) {
2448         COMPILENODE(arg1, &dummy, false);
2449         compileTail();
2450         compileOpcode(opSendSpecialMsg, numArgs);
2451         compileByte(opmIf);
2452     } else if (numArgs == 2) {
2453         arg2 = arg1->mNext;
2454         if (isAnInlineableBlock(arg2)) {
2455             PyrCallNode* callNode = (PyrCallNode*)arg1;
2456             COMPILENODE(callNode->mArglist, &dummy, false);
2457 
2458             trueByteCodes = compileSubExpression((PyrPushLitNode*)arg2, true);
2459             int jumplen = byteCodeLength(trueByteCodes);
2460             if (jumplen) {
2461                 compileByte(143); // special opcodes
2462                 compileByte(flag ? 26 : 27);
2463                 compileByte((jumplen >> 8) & 0xFF);
2464                 compileByte(jumplen & 0xFF);
2465                 compileAndFreeByteCodes(trueByteCodes);
2466             } else {
2467                 compileOpcode(opSpecialOpcode, opcDrop); // drop the value
2468                 compileOpcode(opPushSpecialValue, opsvNil); // push nil
2469             }
2470         } else {
2471             COMPILENODE(arg1, &dummy, false);
2472             COMPILENODE(arg2, &dummy, false);
2473             compileTail();
2474             compileOpcode(opSendSpecialMsg, numArgs);
2475             compileByte(opmIf);
2476         }
2477     } else if (numArgs == 3) {
2478         arg2 = arg1->mNext;
2479         arg3 = arg2->mNext;
2480         if (isAnInlineableBlock(arg2) && isAnInlineableBlock(arg3)) {
2481             PyrCallNode* callNode = (PyrCallNode*)arg1;
2482             COMPILENODE(callNode->mArglist, &dummy, false);
2483 
2484             falseByteCodes = compileSubExpression((PyrPushLitNode*)arg3, true);
2485             int falseLen = byteCodeLength(falseByteCodes);
2486             trueByteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)arg2, falseLen, true);
2487             int trueLen = byteCodeLength(trueByteCodes);
2488             if (falseLen) {
2489                 compileByte(143); // special opcodes
2490                 compileByte(flag ? 24 : 25);
2491                 compileByte((trueLen >> 8) & 0xFF);
2492                 compileByte(trueLen & 0xFF);
2493                 compileAndFreeByteCodes(trueByteCodes);
2494                 compileAndFreeByteCodes(falseByteCodes);
2495             } else if (trueLen) {
2496                 compileByte(143); // special opcodes
2497                 compileByte(flag ? 26 : 27);
2498                 compileByte((trueLen >> 8) & 0xFF);
2499                 compileByte(trueLen & 0xFF);
2500                 compileAndFreeByteCodes(trueByteCodes);
2501             } else {
2502                 compileOpcode(opSpecialOpcode, opcDrop); // drop the boolean
2503                 compileOpcode(opPushSpecialValue, opsvNil); // push nil
2504             }
2505         } else {
2506             COMPILENODE(arg1, &dummy, false);
2507             COMPILENODE(arg2, &dummy, false);
2508             COMPILENODE(arg3, &dummy, false);
2509             compileTail();
2510             compileOpcode(opSendSpecialMsg, numArgs);
2511             compileByte(opmIf);
2512         }
2513     } else {
2514         for (; arg1; arg1 = arg1->mNext) {
2515             COMPILENODE(arg1, &dummy, false);
2516         }
2517         compileTail();
2518         compileOpcode(opSendSpecialMsg, numArgs);
2519         compileByte(opmIf);
2520     }
2521 }
2522 
reverseNodeList(PyrParseNode ** list)2523 PyrParseNode* reverseNodeList(PyrParseNode** list) {
2524     PyrParseNode* temp1 = *list;
2525     PyrParseNode* temp2 = nullptr;
2526     PyrParseNode* temp3 = nullptr;
2527     while (temp1) {
2528         *list = temp1;
2529         temp2 = temp1->mNext;
2530         temp1->mNext = temp3;
2531         temp3 = temp1;
2532         temp1 = temp2;
2533     }
2534     return *list;
2535 }
2536 
2537 
buildCase(PyrParseNode * arg1)2538 PyrCallNode* buildCase(PyrParseNode* arg1) {
2539     // transform case statement into nested if statements.
2540     // int numArgs = nodeListLength(arg1);
2541 
2542     // post("->buildCase %d\n", numArgs);
2543 
2544     PyrParseNode* arg2 = arg1->mNext;
2545 
2546     PyrPushLitNode* litnode = (PyrPushLitNode*)arg1;
2547     PyrBlockNode* bnode = (PyrBlockNode*)slotRawPtr(&litnode->mSlot);
2548     PyrParseNode* bbody = bnode->mBody;
2549     if (bbody->mClassno == pn_DropNode) {
2550         PyrDropNode* dropNode = (PyrDropNode*)bbody;
2551         if (dropNode->mExpr2->mClassno == pn_BlockReturnNode) {
2552             arg1 = dropNode->mExpr1;
2553         } else {
2554             arg1 = dropNode;
2555         }
2556     } else {
2557         arg1 = bbody;
2558     }
2559     arg1->mNext = arg2;
2560 
2561     PyrParseNode* arg3 = nullptr;
2562     if (arg2) {
2563         arg3 = arg2->mNext;
2564         if (arg3) {
2565             PyrParseNode* arg4 = arg3->mNext;
2566             if (arg4) {
2567                 arg3 = buildCase(arg3);
2568                 PyrBlockNode* bnode = newPyrBlockNode(nullptr, nullptr, arg3, false);
2569                 arg3 = newPyrPushLitNode(nullptr, bnode);
2570                 arg2->mNext = arg3;
2571                 arg3->mNext = nullptr;
2572                 arg1->mTail = arg3;
2573             }
2574         } else {
2575             arg1->mTail = arg2;
2576         }
2577     } else {
2578         arg1->mTail = arg1;
2579     }
2580 
2581     /*
2582     post("arg1->mNext %p arg2 %p\n", arg1->mNext, arg2);
2583     if (arg2) {
2584         post("arg2->mNext %p arg3 %p\n", arg2->mNext, arg3);
2585         post("isAnInlineableBlock arg2 %d\n", isAnInlineableBlock(arg2));
2586     }
2587     if (arg3) {
2588         post("isAnInlineableBlock arg3 %d\n", isAnInlineableBlock(arg3));
2589         post("arg3->mNext %p\n", arg3->mNext);
2590     }
2591     DUMPNODE(arg1, 0);
2592     */
2593 
2594     PyrSlot selector;
2595     SetSymbol(&selector, gSpecialSelectors[opmIf]);
2596     PyrSlotNode* selectorNode = newPyrSlotNode(&selector);
2597     PyrCallNode* callNode = newPyrCallNode(selectorNode, arg1, nullptr, nullptr);
2598 
2599     // post("<-buildCase %d\n", numArgs);
2600 
2601     return callNode;
2602 }
2603 
compileCaseMsg(PyrCallNodeBase2 * node)2604 void compileCaseMsg(PyrCallNodeBase2* node) {
2605     PyrParseNode* argnode = node->mArglist;
2606     bool canInline = true;
2607     for (; argnode; argnode = argnode->mNext) {
2608         if (!isAnInlineableBlock(argnode)) {
2609             canInline = false;
2610             break;
2611         }
2612     }
2613     PyrSlot dummy;
2614     if (canInline) {
2615         PyrCallNode* callNode = buildCase(node->mArglist);
2616         callNode->compile(&dummy);
2617     } else {
2618         int numArgs = 0;
2619         argnode = node->mArglist;
2620         for (; argnode; argnode = argnode->mNext, ++numArgs) {
2621             COMPILENODE(argnode, &dummy, false);
2622         }
2623         compileTail();
2624         compileOpcode(opSendSpecialMsg, numArgs);
2625         compileByte(opmCase);
2626     }
2627 }
2628 
compileSwitchMsg(PyrCallNode * node)2629 void compileSwitchMsg(PyrCallNode* node) {
2630     PyrSlot dummy;
2631     bool canInline = true;
2632     int numArgs;
2633     {
2634         PyrParseNode* argnode = node->mArglist;
2635         numArgs = nodeListLength(argnode);
2636 
2637         if (numArgs <= 2) {
2638             error("Missing argument in switch statement");
2639             nodePostErrorLine(node);
2640             compileErrors++;
2641         };
2642 
2643         argnode = argnode->mNext; // skip first arg.
2644 
2645         PyrParseNode* nextargnode = nullptr;
2646         for (; argnode; argnode = nextargnode) {
2647             nextargnode = argnode->mNext;
2648             if (nextargnode != nullptr) {
2649                 if (!isAtomicLiteral(argnode) && !isAnInlineableAtomicLiteralBlock(argnode)) {
2650                     canInline = false;
2651                     break;
2652                 }
2653                 if (!isAnInlineableBlock(nextargnode)) {
2654                     canInline = false;
2655                     break;
2656                 }
2657                 nextargnode = nextargnode->mNext;
2658             } else {
2659                 if (!isAnInlineableBlock(argnode)) {
2660                     canInline = false;
2661                 }
2662                 break;
2663             }
2664         }
2665     }
2666 
2667     if (canInline) {
2668         PyrParseNode* argnode = node->mArglist;
2669 
2670         int flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
2671         int arraySize = NEXTPOWEROFTWO(numArgs * 2);
2672         PyrObject* array = newPyrArray(compileGC(), arraySize, flags, false);
2673         array->size = arraySize;
2674         nilSlots(array->slots, arraySize);
2675 
2676         PyrSlot slot;
2677         SetObject(&slot, array);
2678 
2679         COMPILENODE(argnode, &dummy, false);
2680         compilePushConstant(node, &slot);
2681 
2682         compileByte(143); // lookup slot in dictionary and jump to offset.
2683         compileByte(28);
2684 
2685         argnode = argnode->mNext; // skip first arg.
2686 
2687         PyrParseNode* nextargnode = nullptr;
2688         int absoluteOffset = byteCodeLength(gCompilingByteCodes);
2689         int offset = 0;
2690         int lastOffset = 0;
2691         for (; argnode; argnode = nextargnode) {
2692             nextargnode = argnode->mNext;
2693             if (nextargnode != nullptr) {
2694                 ByteCodes byteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)nextargnode, 0x6666, true);
2695 
2696                 PyrSlot* key;
2697                 PyrSlot value;
2698                 SetInt(&value, offset);
2699                 PyrPushLitNode* keyargnode = (PyrPushLitNode*)argnode;
2700                 if (isAtomicLiteral(argnode)) {
2701                     key = &keyargnode->mSlot;
2702                 } else {
2703                     PyrBlockNode* bnode = (PyrBlockNode*)slotRawPtr(&keyargnode->mSlot);
2704                     PyrDropNode* dropnode = (PyrDropNode*)bnode->mBody;
2705                     PyrPushLitNode* litnode = (PyrPushLitNode*)dropnode->mExpr1;
2706                     key = &litnode->mSlot;
2707                 }
2708 
2709                 int index = arrayAtIdentityHashInPairs(array, key);
2710                 PyrSlot* slot = array->slots + index;
2711                 slotCopy(slot, key);
2712                 SetInt(slot + 1, offset);
2713 
2714                 if (byteCodes) {
2715                     offset += byteCodeLength(byteCodes);
2716                     compileAndFreeByteCodes(byteCodes);
2717                 } else {
2718                     compileOpcode(opPushSpecialValue, opsvNil);
2719                     offset += 1;
2720                 }
2721 
2722                 nextargnode = nextargnode->mNext;
2723                 if (nextargnode == nullptr) {
2724                     compileOpcode(opPushSpecialValue, opsvNil);
2725                     lastOffset = offset;
2726                     offset += 1;
2727                 }
2728             } else {
2729                 ByteCodes byteCodes = compileSubExpressionWithGoto((PyrPushLitNode*)argnode, 0, true);
2730 
2731                 lastOffset = offset;
2732                 if (byteCodes) {
2733                     offset += byteCodeLength(byteCodes);
2734                     compileAndFreeByteCodes(byteCodes);
2735                 } else {
2736                     compileOpcode(opPushSpecialValue, opsvNil);
2737                     lastOffset = offset;
2738                     offset += 1;
2739                 }
2740             }
2741         }
2742 
2743         Byte* bytes = gCompilingByteCodes->bytes + absoluteOffset;
2744         PyrSlot* slots = array->slots;
2745         {
2746             int jumplen = offset - lastOffset;
2747             bytes[lastOffset - 2] = (jumplen >> 8) & 255;
2748             bytes[lastOffset - 1] = jumplen & 255;
2749         }
2750         for (int i = 0; i < arraySize; i += 2) {
2751             PyrSlot* key = slots + i;
2752             PyrSlot* value = key + 1;
2753 
2754             if (IsNil(value)) {
2755                 SetInt(value, lastOffset);
2756             } else {
2757                 int offsetToHere = slotRawInt(value);
2758                 if (offsetToHere) {
2759                     int jumplen = offset - offsetToHere;
2760                     bytes[offsetToHere - 2] = (jumplen >> 8) & 255;
2761                     bytes[offsetToHere - 1] = jumplen & 255;
2762                 }
2763             }
2764         }
2765 
2766     } else {
2767         PyrParseNode* argnode = node->mArglist;
2768         for (; argnode; argnode = argnode->mNext) {
2769             COMPILENODE(argnode, &dummy, false);
2770         }
2771         compileTail();
2772         compileOpcode(opSendSpecialMsg, numArgs);
2773         compileByte(opmSwitch);
2774     }
2775 }
2776 
compileWhileMsg(PyrCallNodeBase2 * node)2777 void compileWhileMsg(PyrCallNodeBase2* node) {
2778     int numArgs;
2779     PyrParseNode* argnode;
2780     PyrSlot dummy;
2781     ByteCodes whileByteCodes, exprByteCodes;
2782     int whileByteCodeLen, exprByteCodeLen;
2783 
2784     numArgs = nodeListLength(node->mArglist);
2785     if (numArgs == 1 && isAnInlineableBlock(node->mArglist)) {
2786         whileByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist, false);
2787 
2788         whileByteCodeLen = byteCodeLength(whileByteCodes);
2789         compileAndFreeByteCodes(whileByteCodes);
2790 
2791         exprByteCodeLen = 1;
2792         compileJump(opcJumpIfFalsePushNil, exprByteCodeLen + 3);
2793 
2794         // opcJumpBak does a drop..
2795         compileOpcode(opPushSpecialValue, opsvNil);
2796 
2797         compileJump(opcJumpBak, exprByteCodeLen + whileByteCodeLen + 4);
2798 
2799     } else if (numArgs == 2 && isWhileTrue(node->mArglist) && isAnInlineableBlock(node->mArglist->mNext)) {
2800         exprByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist->mNext, false);
2801 
2802         exprByteCodeLen = byteCodeLength(exprByteCodes);
2803         compileAndFreeByteCodes(exprByteCodes);
2804 
2805         compileJump(opcJumpBak, exprByteCodeLen + 1);
2806 
2807     } else if (numArgs == 2 && isAnInlineableBlock(node->mArglist) && isAnInlineableBlock(node->mArglist->mNext)) {
2808         whileByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist, false);
2809         exprByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist->mNext, false);
2810 
2811         whileByteCodeLen = byteCodeLength(whileByteCodes);
2812         compileAndFreeByteCodes(whileByteCodes);
2813 
2814         if (exprByteCodes) {
2815             exprByteCodeLen = byteCodeLength(exprByteCodes);
2816             compileJump(opcJumpIfFalsePushNil, exprByteCodeLen + 3);
2817             compileAndFreeByteCodes(exprByteCodes);
2818         } else {
2819             exprByteCodeLen = 1;
2820             compileJump(opcJumpIfFalsePushNil, exprByteCodeLen + 3);
2821             // opcJumpBak does a drop..
2822             compileOpcode(opPushSpecialValue, opsvNil);
2823         }
2824 
2825         compileJump(opcJumpBak, exprByteCodeLen + whileByteCodeLen + 4);
2826 
2827     } else {
2828         argnode = node->mArglist;
2829         for (; argnode; argnode = argnode->mNext) {
2830             COMPILENODE(argnode, &dummy, false);
2831         }
2832         compileTail();
2833         compileOpcode(opSendSpecialMsg, numArgs);
2834         compileByte(opmWhile);
2835     }
2836 }
2837 
compileLoopMsg(PyrCallNodeBase2 * node)2838 void compileLoopMsg(PyrCallNodeBase2* node) {
2839     int numArgs;
2840     PyrParseNode* argnode;
2841     PyrSlot dummy;
2842     ByteCodes exprByteCodes;
2843     int exprByteCodeLen;
2844 
2845     numArgs = nodeListLength(node->mArglist);
2846     if (numArgs == 1 && isAnInlineableBlock(node->mArglist)) {
2847         exprByteCodes = compileSubExpression((PyrPushLitNode*)node->mArglist, false);
2848 
2849         exprByteCodeLen = byteCodeLength(exprByteCodes);
2850         compileAndFreeByteCodes(exprByteCodes);
2851 
2852         compileJump(opcJumpBak, exprByteCodeLen + 1);
2853 
2854     } else {
2855         argnode = node->mArglist;
2856         for (; argnode; argnode = argnode->mNext) {
2857             COMPILENODE(argnode, &dummy, false);
2858         }
2859         compileTail();
2860         compileOpcode(opSendSpecialMsg, numArgs);
2861         compileByte(opmLoop);
2862     }
2863 }
2864 
newPyrBinopCallNode(PyrSlotNode * selector,PyrParseNode * arg1,PyrParseNode * arg2,PyrParseNode * arg3)2865 PyrBinopCallNode* newPyrBinopCallNode(PyrSlotNode* selector, PyrParseNode* arg1, PyrParseNode* arg2,
2866                                       PyrParseNode* arg3) {
2867     PyrBinopCallNode* node = ALLOCNODE(PyrBinopCallNode);
2868     node->mSelector = selector;
2869     node->mArglist = arg1;
2870     arg1->mNext = arg2;
2871     arg2->mNext = arg3;
2872     return node;
2873 }
2874 
isPartialApplication()2875 int PyrBinopCallNode::isPartialApplication() {
2876     int sum = 0;
2877     PyrParseNode* argnode = mArglist;
2878     for (; argnode; argnode = argnode->mNext) {
2879         if (argnode->mClassno == pn_CurryArgNode) {
2880             ((PyrCurryArgNode*)argnode)->mArgNum = sum;
2881             sum++;
2882         }
2883     }
2884     return sum;
2885 }
2886 
compileCall(PyrSlot * result)2887 void PyrBinopCallNode::compileCall(PyrSlot* result) {
2888     int index, selType, isSuper, numArgs;
2889     PyrSlot dummy;
2890 
2891     PyrParseNode* arg1 = mArglist;
2892     PyrParseNode* arg2 = arg1->mNext;
2893     PyrParseNode* arg3 = arg2->mNext;
2894 
2895     // postfl("compilePyrBinopCallNode\n");
2896     isSuper = isSuperObjNode(arg1);
2897     slotRawSymbol(&mSelector->mSlot)->flags |= sym_Called;
2898     index = conjureSelectorIndex((PyrParseNode*)mSelector, gCompilingBlock, isSuper, slotRawSymbol(&mSelector->mSlot),
2899                                  &selType);
2900     numArgs = arg3 ? 3 : 2;
2901     if (isSuper) {
2902         COMPILENODE(arg1, &dummy, false);
2903         COMPILENODE(arg2, &dummy, false);
2904         if (arg3)
2905             COMPILENODE(arg3, &dummy, false);
2906         compileTail();
2907         compileOpcode(opSendSuper, numArgs);
2908         compileByte(index);
2909     } else {
2910         switch (selType) {
2911         case selNormal:
2912             COMPILENODE(arg1, &dummy, false);
2913             COMPILENODE(arg2, &dummy, false);
2914             if (arg3)
2915                 COMPILENODE(arg3, &dummy, false);
2916             compileTail();
2917             compileOpcode(opSendMsg, numArgs);
2918             compileByte(index);
2919             break;
2920         case selSpecial:
2921             COMPILENODE(arg1, &dummy, false);
2922             COMPILENODE(arg2, &dummy, false);
2923             if (arg3)
2924                 COMPILENODE(arg3, &dummy, false);
2925             compileTail();
2926             compileOpcode(opSendSpecialMsg, numArgs);
2927             compileByte(index);
2928             break;
2929         case selUnary:
2930             COMPILENODE(arg1, &dummy, false);
2931             COMPILENODE(arg2, &dummy, false);
2932             if (arg3)
2933                 COMPILENODE(arg3, &dummy, false);
2934             compileTail();
2935             if (arg3)
2936                 compileOpcode(opSpecialOpcode, opcDrop); // drop third argument
2937             compileOpcode(opSpecialOpcode, opcDrop); // drop second argument
2938             compileOpcode(opSendSpecialUnaryArithMsg, index);
2939             break;
2940         case selBinary:
2941             if (arg3) {
2942                 COMPILENODE(arg1, &dummy, false);
2943                 COMPILENODE(arg2, &dummy, false);
2944                 COMPILENODE(arg3, &dummy, false);
2945                 compileTail();
2946                 compileOpcode(opSpecialOpcode, opcSpecialBinaryOpWithAdverb);
2947                 compileByte(index);
2948             } else if (index == opAdd && arg2->mClassno == pn_PushLitNode && IsInt(&((PyrPushLitNode*)arg2)->mSlot)
2949                        && slotRawInt(&((PyrPushLitNode*)arg2)->mSlot) == 1) {
2950                 COMPILENODE(arg1, &dummy, false);
2951                 compileOpcode(opPushSpecialValue, opsvPlusOne);
2952             } else if (index == opSub && arg2->mClassno == pn_PushLitNode && IsInt(&((PyrPushLitNode*)arg2)->mSlot)
2953                        && slotRawInt(&((PyrPushLitNode*)arg2)->mSlot) == 1) {
2954                 COMPILENODE(arg1, &dummy, false);
2955                 compileTail();
2956                 compileOpcode(opPushSpecialValue, opsvMinusOne);
2957             } else {
2958                 COMPILENODE(arg1, &dummy, false);
2959                 COMPILENODE(arg2, &dummy, false);
2960                 compileTail();
2961                 compileOpcode(opSendSpecialBinaryArithMsg, index);
2962             }
2963             break;
2964         case selIf:
2965             compileAnyIfMsg(this);
2966             break;
2967         case selCase:
2968             compileCaseMsg(this);
2969             break;
2970         case selWhile:
2971             compileWhileMsg(this);
2972             break;
2973         case selLoop:
2974             compileLoopMsg(this);
2975             break;
2976         case selAnd:
2977             compileAndMsg(arg1, arg2);
2978             break;
2979         case selOr:
2980             compileOrMsg(arg1, arg2);
2981             break;
2982         case selQuestionMark:
2983             compileQMsg(arg1, arg2);
2984             break;
2985         case selDoubleQuestionMark:
2986             compileQQMsg(arg1, arg2);
2987             break;
2988         case selExclamationQuestionMark:
2989             compileXQMsg(arg1, arg2);
2990             break;
2991         default:
2992             COMPILENODE(arg1, &dummy, false);
2993             COMPILENODE(arg2, &dummy, false);
2994             if (arg3)
2995                 COMPILENODE(arg3, &dummy, false);
2996             compileTail();
2997             compileOpcode(opSendMsg, numArgs);
2998             compileByte(index);
2999             break;
3000         }
3001     }
3002 }
3003 
newPyrPushKeyArgNode(PyrSlotNode * selector,PyrParseNode * expr)3004 PyrPushKeyArgNode* newPyrPushKeyArgNode(PyrSlotNode* selector, PyrParseNode* expr) {
3005     PyrPushKeyArgNode* node = ALLOCNODE(PyrPushKeyArgNode);
3006     node->mSelector = selector;
3007     node->mExpr = expr;
3008     return node;
3009 }
3010 
compile(PyrSlot * result)3011 void PyrPushKeyArgNode::compile(PyrSlot* result) {
3012     PyrSlot dummy;
3013     // postfl("->compilePyrPushKeyArgNode\n");
3014 
3015     compilePushConstant((PyrParseNode*)this, &mSelector->mSlot);
3016 
3017     COMPILENODE(mExpr, &dummy, false);
3018 }
3019 
newPyrDropNode(PyrParseNode * expr1,PyrParseNode * expr2)3020 PyrDropNode* newPyrDropNode(PyrParseNode* expr1, PyrParseNode* expr2) {
3021     PyrDropNode* node = ALLOCNODE(PyrDropNode);
3022     node->mExpr1 = expr1;
3023     node->mExpr2 = expr2;
3024     return node;
3025 }
3026 
compile(PyrSlot * result)3027 void PyrDropNode::compile(PyrSlot* result) {
3028     // postfl("->compilePyrDropNode\n");
3029     PyrSlot dummy;
3030     // eliminate as many drops as possible
3031     if (!mExpr2) {
3032         post("DROP EXPR2 NULL\n");
3033         COMPILENODE(mExpr1, &dummy, true);
3034     } else if (mExpr2->mClassno == pn_BlockReturnNode) {
3035         // no drop before a block return
3036         COMPILENODE(mExpr1, &dummy, true);
3037     } else if (mExpr1 && mExpr1->mClassno == pn_AssignNode) {
3038         // let the store do the drop
3039         ((PyrAssignNode*)mExpr1)->mDrop = 1;
3040         COMPILENODE(mExpr1, &dummy, false);
3041         COMPILENODE(mExpr2, &dummy, true);
3042     } else if (mExpr1 && mExpr1->mClassno == pn_DropNode) {
3043         PyrDropNode* znode;
3044         // let the store do the drop, a bit more complex.
3045         // find the ultimate expression in the left subtree before the drop.
3046         znode = (PyrDropNode*)mExpr1;
3047         while (znode->mExpr2 && znode->mExpr2->mClassno == pn_DropNode) {
3048             znode = (PyrDropNode*)znode->mExpr2;
3049         }
3050         if (znode->mExpr2->mClassno == pn_AssignNode) {
3051             ((PyrAssignNode*)znode->mExpr2)->mDrop = 1;
3052             COMPILENODE(mExpr1, &dummy, false);
3053             COMPILENODE(mExpr2, &dummy, true);
3054         } else {
3055             COMPILENODE(mExpr1, &dummy, false);
3056             compileOpcode(opSpecialOpcode, opcDrop);
3057             COMPILENODE(mExpr2, &dummy, true);
3058         }
3059     } else {
3060         COMPILENODE(mExpr1, &dummy, false);
3061         compileOpcode(opSpecialOpcode, opcDrop);
3062         COMPILENODE(mExpr2, &dummy, true);
3063     }
3064     // postfl("<-compilePyrDropNode\n");
3065 }
3066 
newPyrPushLitNode(PyrSlotNode * literalSlot,PyrParseNode * literalObj)3067 PyrPushLitNode* newPyrPushLitNode(PyrSlotNode* literalSlot, PyrParseNode* literalObj) {
3068     PyrPushLitNode* node;
3069     if (literalSlot) {
3070         node = literalSlot;
3071         node->mClassno = pn_PushLitNode;
3072     } else {
3073         node = ALLOCSLOTNODE(PyrSlotNode, pn_PushLitNode);
3074         SetPtr(&node->mSlot, (PyrObject*)literalObj);
3075     }
3076     return node;
3077 }
3078 
3079 
compilePushConstant(PyrParseNode * node,PyrSlot * slot)3080 void compilePushConstant(PyrParseNode* node, PyrSlot* slot) {
3081     int index = conjureConstantIndex(node, gCompilingBlock, slot);
3082     if (index < (1 << 4)) {
3083         compileByte((opPushLiteral << 4) | index);
3084     } else if (index < (1 << 8)) {
3085         compileByte(40);
3086         compileByte(index & 0xFF);
3087     } else if (index < (1 << 16)) {
3088         compileByte(41);
3089         compileByte((index >> 8) & 0xFF);
3090         compileByte(index & 0xFF);
3091     } else if (index < (1 << 24)) {
3092         compileByte(42);
3093         compileByte((index >> 16) & 0xFF);
3094         compileByte((index >> 8) & 0xFF);
3095         compileByte(index & 0xFF);
3096     } else {
3097         compileByte(43);
3098         compileByte((index >> 24) & 0xFF);
3099         compileByte((index >> 16) & 0xFF);
3100         compileByte((index >> 8) & 0xFF);
3101         compileByte(index & 0xFF);
3102     }
3103 }
3104 
compilePushInt(int value)3105 void compilePushInt(int value) {
3106     // postfl("compilePushInt\n");
3107     if (value >= -1 && value <= 2) {
3108         compileOpcode(opPushSpecialValue, opsvZero + value);
3109     } else {
3110         // printf("int %d\n", value);
3111         if (value >= -(1 << 7) && value <= ((1 << 7) - 1)) {
3112             compileByte(44);
3113             compileByte(value & 0xFF);
3114         } else if (value >= -(1 << 15) && value <= ((1 << 15) - 1)) {
3115             compileByte(45);
3116             compileByte((value >> 8) & 0xFF);
3117             compileByte(value & 0xFF);
3118         } else if (value >= -(1 << 23) && value <= ((1 << 23) - 1)) {
3119             compileByte(46);
3120             compileByte((value >> 16) & 0xFF);
3121             compileByte((value >> 8) & 0xFF);
3122             compileByte(value & 0xFF);
3123         } else {
3124             compileByte(47);
3125             compileByte((value >> 24) & 0xFF);
3126             compileByte((value >> 16) & 0xFF);
3127             compileByte((value >> 8) & 0xFF);
3128             compileByte(value & 0xFF);
3129         }
3130     }
3131 }
3132 
compilePushLit(PyrSlot * result)3133 void PyrSlotNode::compilePushLit(PyrSlot* result) {
3134     int index;
3135     PyrSlot slot;
3136     ByteCodes savedBytes;
3137 
3138     // postfl("compilePyrPushLitNode\n");
3139     if (IsPtr(&mSlot)) {
3140         PyrParseNode* literalObj = (PyrParseNode*)slotRawPtr(&mSlot);
3141         // index = conjureLiteralObjIndex(gCompilingBlock, literalObj);
3142         if (literalObj->mClassno == pn_BlockNode) {
3143             savedBytes = saveByteCodeArray();
3144             COMPILENODE(literalObj, &slot, false);
3145             restoreByteCodeArray(savedBytes);
3146             index = conjureLiteralSlotIndex(literalObj, gCompilingBlock, &slot);
3147             compileOpcode(opExtended, opPushLiteral);
3148             compileByte(index);
3149 
3150             PyrBlock* block = slotRawBlock(&slot);
3151             if (NotNil(&block->contextDef)) {
3152                 METHRAW(gCompilingBlock)->needsHeapContext = 1;
3153             }
3154         } else {
3155             COMPILENODE(literalObj, &slot, false);
3156             compilePushConstant((PyrParseNode*)literalObj, &slot);
3157         }
3158     } else {
3159         slot = mSlot;
3160         if (IsInt(&slot)) {
3161             compilePushInt(slotRawInt(&slot));
3162         } else if (SlotEq(&slot, &o_nil)) {
3163             compileOpcode(opPushSpecialValue, opsvNil);
3164         } else if (SlotEq(&slot, &o_true)) {
3165             compileOpcode(opPushSpecialValue, opsvTrue);
3166         } else if (SlotEq(&slot, &o_false)) {
3167             compileOpcode(opPushSpecialValue, opsvFalse);
3168         } else if (SlotEq(&slot, &o_fhalf)) {
3169             compileOpcode(opPushSpecialValue, opsvFHalf);
3170         } else if (SlotEq(&slot, &o_fnegone)) {
3171             compileOpcode(opPushSpecialValue, opsvFNegOne);
3172         } else if (SlotEq(&slot, &o_fzero)) {
3173             compileOpcode(opPushSpecialValue, opsvFZero);
3174         } else if (SlotEq(&slot, &o_fone)) {
3175             compileOpcode(opPushSpecialValue, opsvFOne);
3176         } else if (SlotEq(&slot, &o_ftwo)) {
3177             compileOpcode(opPushSpecialValue, opsvFTwo);
3178         } else if (SlotEq(&slot, &o_inf)) {
3179             compileOpcode(opPushSpecialValue, opsvInf);
3180         } else if (IsFloat(&slot)) {
3181             compilePushConstant((PyrParseNode*)this, &slot);
3182         } else if (IsSym(&slot)) {
3183             compilePushConstant((PyrParseNode*)this, &slot);
3184         } else {
3185             compilePushConstant((PyrParseNode*)this, &slot);
3186         }
3187     }
3188 }
3189 
newPyrLiteralNode(PyrSlotNode * literalSlot,PyrParseNode * literalObj)3190 PyrLiteralNode* newPyrLiteralNode(PyrSlotNode* literalSlot, PyrParseNode* literalObj) {
3191     PyrLiteralNode* node;
3192     if (literalSlot) {
3193         node = literalSlot;
3194         node->mClassno = pn_LiteralNode;
3195     } else {
3196         node = ALLOCSLOTNODE(PyrSlotNode, pn_LiteralNode);
3197         SetPtr(&node->mSlot, (PyrObject*)literalObj);
3198     }
3199     return node;
3200 }
3201 
compilePyrLiteralNode(PyrLiteralNode * node,PyrSlot * result)3202 void compilePyrLiteralNode(PyrLiteralNode* node, PyrSlot* result) {
3203     if (!node) {
3204         SetNil(result);
3205     } else {
3206         node->compileLiteral(result);
3207     }
3208 }
3209 
compileLiteral(PyrSlot * result)3210 void PyrSlotNode::compileLiteral(PyrSlot* result) {
3211     ByteCodes savedBytes;
3212 
3213     if (IsPtr(&mSlot)) {
3214         PyrParseNode* literalObj = (PyrParseNode*)slotRawPtr(&mSlot);
3215         if (literalObj->mClassno == pn_BlockNode) {
3216             savedBytes = saveByteCodeArray();
3217             COMPILENODE(literalObj, result, false);
3218             restoreByteCodeArray(savedBytes);
3219 
3220             PyrBlock* block = slotRawBlock(result);
3221             if (NotNil(&block->contextDef)) {
3222                 METHRAW(gCompilingBlock)->needsHeapContext = 1;
3223             }
3224         } else {
3225             COMPILENODE(literalObj, result, false);
3226         }
3227     } else {
3228         *(PyrSlot*)result = mSlot;
3229     }
3230 }
3231 
newPyrReturnNode(PyrParseNode * expr)3232 PyrReturnNode* newPyrReturnNode(PyrParseNode* expr) {
3233     PyrReturnNode* node = ALLOCNODE(PyrReturnNode);
3234     node->mExpr = expr;
3235     return node;
3236 }
3237 
3238 
compile(PyrSlot * result)3239 void PyrReturnNode::compile(PyrSlot* result) {
3240     PyrPushLitNode* lit;
3241     PyrSlot dummy;
3242 
3243     // post("->compilePyrReturnNode\n");
3244     gFunctionCantBeClosed = true;
3245     if (!mExpr) {
3246         compileOpcode(opSpecialOpcode, opcReturnSelf);
3247     } else if (mExpr->mClassno == pn_PushLitNode) {
3248         lit = (PyrPushLitNode*)mExpr;
3249         if (IsSym(&(lit->mSlot)) && slotRawSymbol(&lit->mSlot) == s_this) {
3250             compileOpcode(opSpecialOpcode, opcReturnSelf);
3251         } else if (IsNil(&lit->mSlot)) {
3252             compileOpcode(opSpecialOpcode, opcReturnNil);
3253         } else if (IsTrue(&lit->mSlot)) {
3254             compileOpcode(opSpecialOpcode, opcReturnTrue);
3255         } else if (IsFalse(&lit->mSlot)) {
3256             compileOpcode(opSpecialOpcode, opcReturnFalse);
3257         } else {
3258             COMPILENODE(lit, &dummy, false);
3259             compileOpcode(opSpecialOpcode, opcReturn);
3260         }
3261     } else {
3262         SetTailBranch branch(true);
3263         SetTailIsMethodReturn mr(true);
3264         COMPILENODE(mExpr, &dummy, true);
3265         compileOpcode(opSpecialOpcode, opcReturn);
3266     }
3267     // post("<-compilePyrReturnNode\n");
3268 }
3269 
newPyrBlockReturnNode()3270 PyrBlockReturnNode* newPyrBlockReturnNode() {
3271     PyrBlockReturnNode* node = ALLOCNODE(PyrBlockReturnNode);
3272     return node;
3273 }
3274 
3275 
compile(PyrSlot * result)3276 void PyrBlockReturnNode::compile(PyrSlot* result) {
3277     // postfl("compilePyrBlockReturnNode\n");
3278     // compileOpcode(opSpecialOpcode, opcFunctionReturn);
3279 }
3280 
newPyrAssignNode(PyrSlotNode * varName,PyrParseNode * expr,int flags)3281 PyrAssignNode* newPyrAssignNode(PyrSlotNode* varName, PyrParseNode* expr, int flags) {
3282     PyrAssignNode* node = ALLOCNODE(PyrAssignNode);
3283     node->mVarName = varName;
3284     node->mExpr = expr;
3285     node->mDrop = 0;
3286     return node;
3287 }
3288 
newPyrSetterNode(PyrSlotNode * selector,PyrParseNode * expr1,PyrParseNode * expr2)3289 PyrSetterNode* newPyrSetterNode(PyrSlotNode* selector, PyrParseNode* expr1, PyrParseNode* expr2) {
3290     PyrSetterNode* node = ALLOCNODE(PyrSetterNode);
3291     node->mSelector = selector;
3292     node->mExpr1 = expr1;
3293     node->mExpr2 = expr2;
3294     return node;
3295 }
3296 
newPyrMultiAssignNode(PyrMultiAssignVarListNode * varList,PyrParseNode * expr,int flags)3297 PyrMultiAssignNode* newPyrMultiAssignNode(PyrMultiAssignVarListNode* varList, PyrParseNode* expr, int flags) {
3298     PyrMultiAssignNode* node = ALLOCNODE(PyrMultiAssignNode);
3299     node->mVarList = varList;
3300     node->mExpr = expr;
3301     node->mDrop = 0;
3302     return node;
3303 }
3304 
newPyrMultiAssignVarListNode(PyrSlotNode * varNames,PyrSlotNode * rest)3305 PyrMultiAssignVarListNode* newPyrMultiAssignVarListNode(PyrSlotNode* varNames, PyrSlotNode* rest) {
3306     PyrMultiAssignVarListNode* node = ALLOCNODE(PyrMultiAssignVarListNode);
3307     node->mVarNames = varNames;
3308     node->mRest = rest;
3309     return node;
3310 }
3311 
compileAssignVar(PyrParseNode * node,PyrSymbol * varName,bool drop)3312 void compileAssignVar(PyrParseNode* node, PyrSymbol* varName, bool drop) {
3313     int level, index, vindex, varType;
3314     PyrBlock* tempfunc;
3315     PyrClass* classobj;
3316 
3317     // postfl("compileAssignVar\n");
3318     classobj = gCompilingClass;
3319     if (varName == s_this || varName == s_super || varName == s_curProcess || varName == s_curThread
3320         || varName == s_curMethod || varName == s_curBlock || varName == s_curClosure) {
3321         error("You may not assign to '%s'.", varName->name);
3322         nodePostErrorLine(node);
3323         compileErrors++;
3324     } else if (varName->name[0] >= 'A' && varName->name[0] <= 'Z') {
3325         // actually this shouldn't even parse, so you won't get here.
3326         error("You may not assign to a class name.");
3327         nodePostErrorLine(node);
3328         compileErrors++;
3329     } else if (findVarName(gCompilingBlock, &classobj, varName, &varType, &level, &index, &tempfunc)) {
3330         switch (varType) {
3331         case varInst:
3332             if (drop) {
3333                 if (index <= 15) {
3334                     compileByte((opStoreInstVar << 4) | index);
3335                 } else {
3336                     compileByte(opStoreInstVar);
3337                     compileByte(index);
3338                     compileByte((opSpecialOpcode << 4) | opcDrop);
3339                 }
3340             } else {
3341                 compileByte(opStoreInstVar);
3342                 compileByte(index);
3343             }
3344             break;
3345         case varClass: {
3346             index += slotRawInt(&classobj->classVarIndex);
3347             if (drop) {
3348                 if (index < 4096) {
3349                     compileByte((opStoreClassVar << 4) | ((index >> 8) & 15));
3350                     compileByte(index & 255);
3351                 } else {
3352                     compileByte(opStoreClassVar);
3353                     assert(false);
3354                     vindex = 0;
3355                     compileByte(vindex); // FIXME: vindex is not initalized!!!!
3356                     compileByte(index);
3357                     compileByte((opSpecialOpcode << 4) | opcDrop);
3358                 }
3359             } else {
3360                 compileByte(opStoreClassVar);
3361                 compileByte((index >> 8) & 255);
3362                 compileByte(index & 255);
3363             }
3364         } break;
3365         case varConst: {
3366             error("You may not assign to a constant.");
3367             nodePostErrorLine(node);
3368             compileErrors++;
3369         } break;
3370         case varTemp:
3371             // compileOpcode(opStoreTempVar, level);
3372             // compileByte(index);
3373             if (drop) {
3374                 if (index <= 15 && level < 8) {
3375                     compileByte((opStoreTempVar << 4) | level);
3376                     compileByte(index);
3377                 } else {
3378                     compileByte(opStoreTempVar);
3379                     compileByte(level);
3380                     compileByte(index);
3381                     compileByte((opSpecialOpcode << 4) | opcDrop);
3382                 }
3383             } else {
3384                 compileByte(opStoreTempVar);
3385                 compileByte(level);
3386                 compileByte(index);
3387             }
3388             break;
3389         }
3390     } else {
3391         error("Variable '%s' not defined.\n", varName->name);
3392         nodePostErrorLine(node);
3393         compileErrors++;
3394         // Debugger();
3395     }
3396 }
3397 
compile(PyrSlot * result)3398 void PyrAssignNode::compile(PyrSlot* result) {
3399     PyrSlot dummy;
3400 
3401     // postfl("compilePyrAssignNode\n");
3402     COMPILENODE(mExpr, &dummy, false);
3403     compileAssignVar((PyrParseNode*)this, slotRawSymbol(&mVarName->mSlot), mDrop);
3404 }
3405 
3406 
isPartialApplication()3407 int PyrSetterNode::isPartialApplication() {
3408     int sum = 0;
3409     if (mExpr1->mClassno == pn_CurryArgNode) {
3410         ((PyrCurryArgNode*)mExpr1)->mArgNum = sum;
3411         sum++;
3412     }
3413     if (mExpr2->mClassno == pn_CurryArgNode) {
3414         ((PyrCurryArgNode*)mExpr2)->mArgNum = sum;
3415         sum++;
3416     }
3417     return sum;
3418 }
3419 
compileCall(PyrSlot * result)3420 void PyrSetterNode::compileCall(PyrSlot* result) {
3421     int index, selType, isSuper;
3422     PyrSlot dummy;
3423     char setterName[128];
3424     PyrSymbol* setterSym;
3425 
3426     // postfl("compilePyrSetterNode\n");
3427     if (nodeListLength(mExpr1) > 1) {
3428         error("Setter method called with too many arguments.\n");
3429         nodePostErrorLine(mExpr1);
3430         compileErrors++;
3431     } else {
3432         COMPILENODE(mExpr1, &dummy, false);
3433         COMPILENODE(mExpr2, &dummy, false);
3434 
3435 
3436         // postfl("compilePyrCallNode\n");
3437         isSuper = isSuperObjNode(mExpr1);
3438 
3439         sprintf(setterName, "%s_", slotRawSymbol(&mSelector->mSlot)->name);
3440         setterSym = getsym(setterName);
3441 
3442         slotRawSymbol(&mSelector->mSlot)->flags |= sym_Called;
3443         index = conjureSelectorIndex((PyrParseNode*)mSelector, gCompilingBlock, isSuper, setterSym, &selType);
3444         if (isSuper) {
3445             compileTail();
3446             compileOpcode(opSendSuper, 2);
3447             compileByte(index);
3448         } else {
3449             compileTail();
3450             compileOpcode(opSendMsg, 2);
3451             compileByte(index);
3452         }
3453     }
3454 }
3455 
compile(PyrSlot * result)3456 void PyrMultiAssignNode::compile(PyrSlot* result) {
3457     PyrSlot dummy;
3458 
3459     // postfl("compilePyrMultiAssignNode\n");
3460     COMPILENODE(mExpr, &dummy, false);
3461     COMPILENODE(mVarList, &dummy, false);
3462 }
3463 
compile(PyrSlot * result)3464 void PyrMultiAssignVarListNode::compile(PyrSlot* result) {
3465     int i, numAssigns;
3466     PyrSlotNode* varname;
3467 
3468     // postfl("compilePyrMultiAssignVarListNode\n");
3469     numAssigns = nodeListLength((PyrParseNode*)mVarNames);
3470     varname = mVarNames;
3471     for (i = 0; i < numAssigns; ++i, varname = (PyrSlotNode*)varname->mNext) {
3472         compileOpcode(opSpecialOpcode, opcDup);
3473         compilePushInt(i);
3474         compileOpcode(opSendSpecialMsg, 2);
3475         compileByte(opmAt);
3476         compileAssignVar((PyrParseNode*)varname, slotRawSymbol(&varname->mSlot), 1);
3477         // compileOpcode(opSpecialOpcode, opcDrop);
3478     }
3479     if (mRest) {
3480         compileOpcode(opSpecialOpcode, opcDup);
3481         compilePushInt(i);
3482         compileOpcode(opSendSpecialMsg, 2);
3483         compileByte(opmCopyToEnd);
3484         compileAssignVar((PyrParseNode*)mRest, slotRawSymbol(&mRest->mSlot), 1);
3485         // compileOpcode(opSpecialOpcode, opcDrop);
3486     }
3487 }
3488 
3489 
newPyrDynDictNode(PyrParseNode * elems)3490 PyrDynDictNode* newPyrDynDictNode(PyrParseNode* elems) {
3491     PyrDynDictNode* node;
3492 
3493     // if (compilingCmdLine) post("newPyrDynDictNode\n");
3494     node = ALLOCNODE(PyrDynDictNode);
3495     node->mElems = elems;
3496     return node;
3497 }
3498 
isPartialApplication()3499 int PyrDynDictNode::isPartialApplication() {
3500     int sum = 0;
3501     int numItems = nodeListLength(mElems);
3502     PyrParseNode* inode = mElems;
3503     for (int i = 0; i < numItems; ++i) {
3504         if (inode->mClassno == pn_CurryArgNode) {
3505             ((PyrCurryArgNode*)inode)->mArgNum = sum;
3506             sum++;
3507         }
3508         inode = (PyrParseNode*)inode->mNext;
3509     }
3510     return sum;
3511 }
3512 
compileCall(PyrSlot * result)3513 void PyrDynDictNode::compileCall(PyrSlot* result) {
3514     int i, numItems;
3515     PyrParseNode* inode;
3516     PyrSlot dummy;
3517 
3518     // postfl("compilePyrDynDictNode\n");
3519     numItems = nodeListLength(mElems) >> 1;
3520 
3521     compilePushVar((PyrParseNode*)this, s_event);
3522 
3523     compilePushInt(numItems);
3524     compileByte(110); // push nil for proto
3525     compileByte(110); // push nil for parent
3526     compileByte(108); // push true for know
3527     compileOpcode(opSendSpecialMsg, 5);
3528 
3529     compileByte(opmNew);
3530 
3531     inode = mElems;
3532     for (i = 0; i < numItems; ++i) {
3533         // if (compilingCmdLine) post("+ %d %d\n", i, gCompilingByteCodes->size);
3534         COMPILENODE(inode, &dummy, false);
3535         inode = (PyrParseNode*)inode->mNext;
3536         COMPILENODE(inode, &dummy, false);
3537         inode = (PyrParseNode*)inode->mNext;
3538         compileOpcode(opSendSpecialMsg, 3);
3539         compileByte(opmPut);
3540     }
3541 }
3542 
newPyrDynListNode(PyrParseNode * classname,PyrParseNode * elems)3543 PyrDynListNode* newPyrDynListNode(PyrParseNode* classname, PyrParseNode* elems) {
3544     PyrDynListNode* node;
3545 
3546     // if (compilingCmdLine) post("newPyrDynListNode\n");
3547     node = ALLOCNODE(PyrDynListNode);
3548     node->mClassname = classname;
3549     node->mElems = elems;
3550     return node;
3551 }
3552 
isPartialApplication()3553 int PyrDynListNode::isPartialApplication() {
3554     int sum = 0;
3555     int numItems = nodeListLength(mElems);
3556     PyrParseNode* inode = mElems;
3557     for (int i = 0; i < numItems; ++i) {
3558         if (inode->mClassno == pn_CurryArgNode) {
3559             ((PyrCurryArgNode*)inode)->mArgNum = sum;
3560             sum++;
3561         }
3562         inode = (PyrParseNode*)inode->mNext;
3563     }
3564     return sum;
3565 }
3566 
compileCall(PyrSlot * result)3567 void PyrDynListNode::compileCall(PyrSlot* result) {
3568     int i, numItems;
3569     PyrParseNode* inode;
3570     PyrSlot dummy;
3571 
3572     // postfl("compilePyrDynListNode\n");
3573     numItems = nodeListLength(mElems);
3574 
3575     if (mClassname) {
3576         compilePushVar((PyrParseNode*)this, slotRawSymbol(&((PyrSlotNode*)mClassname)->mSlot));
3577     } else {
3578         compilePushVar((PyrParseNode*)this, s_array);
3579     }
3580 
3581     // compileOpcode(opExtended, opPushSpecialValue);
3582     // compileByte(op_class_list);
3583 
3584     compilePushInt(numItems);
3585 
3586     compileOpcode(opSendSpecialMsg, 2);
3587     compileByte(opmNew);
3588 
3589     inode = mElems;
3590     for (i = 0; i < numItems; ++i, inode = (PyrParseNode*)inode->mNext) {
3591         // if (compilingCmdLine) post("+ %d %d\n", i, gCompilingByteCodes->size);
3592         COMPILENODE(inode, &dummy, false);
3593         compileOpcode(opSendSpecialMsg, 2);
3594         compileByte(opmAdd);
3595     }
3596 }
3597 
newPyrLitListNode(PyrParseNode * classname,PyrParseNode * elems)3598 PyrLitListNode* newPyrLitListNode(PyrParseNode* classname, PyrParseNode* elems) {
3599     PyrLitListNode* node = ALLOCNODE(PyrLitListNode);
3600     node->mClassname = classname;
3601     node->mElems = elems;
3602     return node;
3603 }
3604 
compile(PyrSlot * result)3605 void PyrLitListNode::compile(PyrSlot* result) {
3606     PyrSlot* resultSlot;
3607     PyrSlot itemSlot;
3608     PyrObject* array;
3609     PyrParseNode* inode;
3610     int i, numItems, flags;
3611 
3612     // postfl("->compilePyrLitListNode\n");
3613     if (mClassname && slotRawSymbol(&((PyrSlotNode*)mClassname)->mSlot) != s_array) {
3614         error("Only Array is supported as literal type.\n");
3615         post("Compiling as an Array.\n");
3616     }
3617     resultSlot = (PyrSlot*)result;
3618     numItems = mElems ? nodeListLength(mElems) : 0;
3619     flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
3620     array = newPyrArray(compileGC(), numItems, flags, false);
3621     inode = mElems;
3622     for (i = 0; i < numItems; ++i, inode = (PyrParseNode*)inode->mNext) {
3623         COMPILENODE(inode, &itemSlot, false);
3624         array->slots[i] = itemSlot;
3625     }
3626     array->size = numItems;
3627     SetObject(resultSlot, array);
3628     // postfl("<-compilePyrLitListNode\n");
3629 }
3630 
3631 
newPyrLitDictNode(PyrParseNode * elems)3632 PyrLitDictNode* newPyrLitDictNode(PyrParseNode* elems) {
3633     PyrLitDictNode* node = ALLOCNODE(PyrLitDictNode);
3634     node->mElems = elems;
3635 
3636     return node;
3637 }
3638 
3639 int litDictPut(PyrObject* dict, PyrSlot* key, PyrSlot* value);
litDictPut(PyrObject * dict,PyrSlot * key,PyrSlot * value)3640 int litDictPut(PyrObject* dict, PyrSlot* key, PyrSlot* value) {
3641 #if 0
3642 	PyrSlot *slot, *newslot;
3643 	int i, index, size;
3644 	PyrObject *array;
3645 
3646 	bool knows = IsTrue(dict->slots + ivxIdentDict_know);
3647 	if (knows && IsSym(key)) {
3648 		if (slotRawSymbol(key) == s_parent) {
3649 			slotCopy(&dict->slots[ivxIdentDict_parent], value);
3650 			return errNone;
3651 		}
3652 		if (slotRawSymbol(key) == s_proto) {
3653 			slotCopy(&dict->slots[ivxIdentDict_proto], value);
3654 			return errNone;
3655 		}
3656 	}
3657 	array = slotRawObject(&dict->slots[ivxIdentDict_array]);
3658 	if (!isKindOf((PyrObject*)array, class_array)) return errFailed;
3659 
3660 	index = arrayAtIdentityHashInPairs(array, key);
3661 	slot = array->slots + index;
3662 	slotCopy(&slot[1], value);
3663 	if (IsNil(slot)) {
3664 		slotCopy(slot, key);
3665 	}
3666 #endif
3667     return errNone;
3668 }
3669 
3670 
dump(int level)3671 void PyrLitDictNode::dump(int level) {}
3672 
compile(PyrSlot * result)3673 void PyrLitDictNode::compile(PyrSlot* result) {
3674 #if 0
3675 	PyrSlot *resultSlot;
3676 	PyrSlot itemSlot;
3677 	PyrObject *array;
3678 	PyrParseNode *inode;
3679 	int i, numItems, flags;
3680 
3681 	//postfl("->compilePyrLitDictNode\n");
3682 	if (mClassname && slotRawSymbol(&((PyrSlotNode*)mClassname)->mSlot) != s_array) {
3683 		error("Only Array is supported as literal type.\n");
3684 		post("Compiling as an Array.\n");
3685 	}
3686 	resultSlot = (PyrSlot*)result;
3687 	numItems = mElems ? nodeListLength(mElems) : 0;
3688 	int numSlots = NEXTPOWEROFTWO(numItems*2);
3689 
3690     PyrObject *obj = instantiateObject(g->gc, class_event->u.classobj, 0, true, false);
3691     PyrSlot *slots = obj->slots;
3692 
3693 	flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
3694 	array = newPyrArray(compileGC(), numSlots, flags, false);
3695 	nilSlots(array->slots, numSlots);
3696 	inode = mElems;
3697 	for (i=0; i<numItems; ++i, inode = (PyrParseNode*)inode->mNext) {
3698 		COMPILENODE(inode, &itemSlot, false);
3699 		array->slots[i] = itemSlot;
3700 	}
3701 	array->size = numItems;
3702 	SetObject(resultSlot, array);
3703 	//postfl("<-compilePyrLitListNode\n");
3704 #endif
3705 }
3706 
3707 
3708 extern LongStack closedFuncCharNo;
3709 extern int lastClosedFuncCharNo;
3710 
newPyrBlockNode(PyrArgListNode * arglist,PyrVarListNode * varlist,PyrParseNode * body,bool isTopLevel)3711 PyrBlockNode* newPyrBlockNode(PyrArgListNode* arglist, PyrVarListNode* varlist, PyrParseNode* body, bool isTopLevel) {
3712     PyrBlockNode* node = ALLOCNODE(PyrBlockNode);
3713     node->mArglist = arglist;
3714     catVarLists(varlist);
3715     node->mVarlist = varlist;
3716     node->mBody = body;
3717     node->mIsTopLevel = isTopLevel;
3718 
3719     node->mBeginCharNo = lastClosedFuncCharNo;
3720 
3721     return node;
3722 }
3723 
compile(PyrSlot * slotResult)3724 void PyrBlockNode::compile(PyrSlot* slotResult) {
3725     PyrBlock *block, *prevBlock;
3726     PyrMethodRaw* methraw;
3727     int i, j, numArgs, numVars, funcVarArgs;
3728     int numSlots, numArgNames, flags;
3729     PyrVarDefNode* vardef;
3730     PyrObject* proto;
3731     PyrSymbolArray *argNames, *varNames;
3732     PyrSlot dummy;
3733     bool hasVarExprs = false;
3734 
3735     // postfl("->block\n");
3736 
3737     // create a new block object
3738 
3739     flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
3740     block = newPyrBlock(flags);
3741     SetObject(slotResult, block);
3742 
3743     int prevFunctionHighestExternalRef = gFunctionHighestExternalRef;
3744     bool prevFunctionCantBeClosed = gFunctionCantBeClosed;
3745     gFunctionHighestExternalRef = 0;
3746     gFunctionCantBeClosed = false;
3747 
3748     prevBlock = gCompilingBlock;
3749     PyrClass* prevClass = gCompilingClass;
3750 
3751     gCompilingBlock = block;
3752     PyrBlock* prevPartiallyAppliedFunction = gPartiallyAppliedFunction;
3753     gPartiallyAppliedFunction = nullptr;
3754 
3755     methraw = METHRAW(block);
3756     methraw->unused1 = 0;
3757     methraw->unused2 = 0;
3758 
3759     int endCharNo = linestarts[mLineno] + mCharno;
3760     int stringLength = endCharNo - mBeginCharNo;
3761     int lastChar = text[mBeginCharNo + stringLength - 1];
3762     if (lastChar == 0)
3763         stringLength--;
3764 
3765     methraw->needsHeapContext = 0;
3766     if (mIsTopLevel) {
3767         gCompilingClass = class_interpreter;
3768         SetNil(&block->contextDef);
3769     } else {
3770         SetObject(&block->contextDef, prevBlock);
3771     }
3772 
3773     methraw->varargs = funcVarArgs = (mArglist && mArglist->mRest) ? 1 : 0;
3774     numArgs = mArglist ? nodeListLength((PyrParseNode*)mArglist->mVarDefs) : 0;
3775     numVars = mVarlist ? nodeListLength((PyrParseNode*)mVarlist->mVarDefs) : 0;
3776 
3777     if (numArgs > 255) {
3778         error("Too many arguments in function definition (> 255)\n");
3779         nodePostErrorLine((PyrParseNode*)mArglist->mVarDefs);
3780         compileErrors++;
3781     }
3782 
3783     if (numArgs > 255) {
3784         error("Too many arguments in function definition (> 255).\n");
3785         nodePostErrorLine((PyrParseNode*)mArglist->mVarDefs);
3786         compileErrors++;
3787     }
3788 
3789     numSlots = numArgs + funcVarArgs + numVars;
3790     methraw->frameSize = (numSlots + FRAMESIZE) * sizeof(PyrSlot);
3791     if (numSlots) {
3792         proto = newPyrArray(compileGC(), numSlots, flags, false);
3793         proto->size = numSlots;
3794         SetObject(&block->prototypeFrame, proto);
3795     } else {
3796         SetNil(&block->prototypeFrame);
3797     }
3798 
3799     numArgNames = numArgs + funcVarArgs;
3800 
3801     if (numArgNames) {
3802         argNames = newPyrSymbolArray(compileGC(), numArgNames, flags, false);
3803         argNames->size = numArgNames;
3804         SetObject(&block->argNames, argNames);
3805     } else {
3806         SetNil(&block->argNames);
3807     }
3808 
3809     if (numVars) {
3810         varNames = newPyrSymbolArray(compileGC(), numVars, flags, false);
3811         varNames->size = numVars;
3812         SetObject(&block->varNames, varNames);
3813     } else {
3814         SetNil(&block->varNames);
3815     }
3816 
3817     methraw->numargs = numArgs;
3818     methraw->numvars = numVars;
3819     methraw->posargs = numArgs + funcVarArgs;
3820     methraw->numtemps = numSlots;
3821     methraw->popSize = numSlots;
3822 
3823     // declare args
3824     if (numArgs) {
3825         PyrSymbol** blockargs;
3826         blockargs = slotRawSymbolArray(&block->argNames)->symbols;
3827         vardef = mArglist->mVarDefs;
3828         for (i = 0; i < numArgs; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
3829             PyrSlot* varslot;
3830             varslot = &vardef->mVarName->mSlot;
3831             // already declared as arg?
3832             for (j = 0; j < i; ++j) {
3833                 if (blockargs[j] == slotRawSymbol(varslot)) {
3834                     error("Function argument '%s' already declared in %s:%s\n", slotRawSymbol(varslot)->name,
3835                           slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name);
3836                     nodePostErrorLine((PyrParseNode*)vardef);
3837                     compileErrors++;
3838                 }
3839             }
3840             // put it in mArglist
3841             blockargs[i] = slotRawSymbol(varslot);
3842             // postfl("defarg %d '%s'\n", i, slotRawSymbol(slot)->name);
3843         }
3844     }
3845 
3846     if (funcVarArgs) {
3847         PyrSlot* varslot;
3848         PyrSymbol** blockargs;
3849         blockargs = slotRawSymbolArray(&block->argNames)->symbols;
3850         varslot = &mArglist->mRest->mSlot;
3851         // already declared as arg?
3852         for (j = 0; j < numArgs; ++j) {
3853             if (blockargs[j] == slotRawSymbol(varslot)) {
3854                 error("Function argument '%s' already declared in %s:%s\n", slotRawSymbol(varslot)->name,
3855                       slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name);
3856                 nodePostErrorLine((PyrParseNode*)vardef);
3857                 compileErrors++;
3858             }
3859         }
3860         // put it in mArglist
3861         blockargs[numArgs] = slotRawSymbol(varslot);
3862         // postfl("defrest '%s'\n", slotRawSymbol(slot)->name);
3863     }
3864 
3865     // declare vars
3866     if (numVars) {
3867         PyrSymbol **blockargs, **blockvars;
3868         blockargs = slotRawSymbolArray(&block->argNames)->symbols;
3869         blockvars = slotRawSymbolArray(&block->varNames)->symbols;
3870         vardef = mVarlist->mVarDefs;
3871         for (i = 0; i < numVars; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
3872             PyrSlot* varslot;
3873             varslot = &vardef->mVarName->mSlot;
3874             // already declared as arg?
3875             for (j = 0; j < numArgNames; ++j) {
3876                 if (blockargs[j] == slotRawSymbol(varslot)) {
3877                     error("Function variable '%s' already declared in %s:%s\n", slotRawSymbol(varslot)->name,
3878                           slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name);
3879                     nodePostErrorLine((PyrParseNode*)vardef);
3880                     compileErrors++;
3881                 }
3882             }
3883             // already declared as var?
3884             for (j = 0; j < i; ++j) {
3885                 if (blockvars[j] == slotRawSymbol(varslot)) {
3886                     error("Function variable '%s' already declared in %s:%s\n", slotRawSymbol(varslot)->name,
3887                           slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name);
3888                     nodePostErrorLine((PyrParseNode*)vardef);
3889                     compileErrors++;
3890                 }
3891             }
3892             // put it in varlist
3893             blockvars[i] = slotRawSymbol(varslot);
3894             // postfl("defvar %d '%s'\n", i, slotRawSymbol(slot)->name);
3895         }
3896     }
3897 
3898     if (numArgs) {
3899         vardef = mArglist->mVarDefs;
3900         for (i = 0; i < numArgs; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
3901             PyrSlot *slot, litval;
3902             slot = slotRawObject(&block->prototypeFrame)->slots + i;
3903             if (vardef->hasExpr(&litval))
3904                 hasVarExprs = true;
3905             // compilePyrLiteralNode((PyrLiteralNode*)vardef->mDefVal, &litval);
3906             *slot = litval;
3907         }
3908     }
3909 
3910     if (funcVarArgs) {
3911         // SetNil(&slotRawObject(&block->prototypeFrame)->slots[numArgs]);
3912         slotCopy(&slotRawObject(&block->prototypeFrame)->slots[numArgs], &o_emptyarray);
3913     }
3914 
3915     if (numVars) {
3916         vardef = mVarlist->mVarDefs;
3917         for (i = 0; i < numVars; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
3918             PyrSlot *slot, litval;
3919             slot = slotRawObject(&block->prototypeFrame)->slots + i + numArgs + funcVarArgs;
3920             if (vardef->hasExpr(&litval))
3921                 hasVarExprs = true;
3922             // compilePyrLiteralNode(vardef->mDefVal, &litval);
3923             *slot = litval;
3924         }
3925     }
3926     methraw->methType = methBlock;
3927 
3928     // compile body
3929     initByteCodes();
3930     {
3931         SetTailBranch branch(true);
3932         /*if (compilingCmdLine) {
3933             post("block %d\n", gIsTailCodeBranch);
3934             DUMPNODE(mBody, 0);
3935         }*/
3936         SetTailIsMethodReturn mr(false);
3937         if (hasVarExprs) {
3938             if (mArglist) {
3939                 vardef = mArglist->mVarDefs;
3940                 for (i = 0; i < numArgs; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
3941                     vardef->compileArg(&dummy);
3942                 }
3943             }
3944             if (mVarlist) {
3945                 vardef = mVarlist->mVarDefs;
3946                 for (i = 0; i < numVars; ++i, vardef = (PyrVarDefNode*)vardef->mNext) {
3947                     vardef->compile(&dummy);
3948                 }
3949             }
3950         }
3951         if (mBody->mClassno == pn_BlockReturnNode) {
3952             compileOpcode(opPushSpecialValue, opsvNil);
3953         } else {
3954             COMPILENODE(mBody, &dummy, true);
3955         }
3956     }
3957     compileOpcode(opSpecialOpcode, opcFunctionReturn);
3958     installByteCodes(block);
3959 
3960     if ((!gFunctionCantBeClosed && gFunctionHighestExternalRef == 0) || mIsTopLevel) {
3961         SetNil(&block->contextDef);
3962 
3963         PyrString* string = newPyrStringN(compileGC(), stringLength, flags, false);
3964         memcpy(string->s, text + mBeginCharNo, stringLength);
3965         SetObject(&block->sourceCode, string);
3966         // static int totalLength = 0, totalStrings = 0;
3967         // totalLength += stringLength;
3968         // totalStrings++;
3969         // post("cf %4d %4d %6d %s:%s \n", totalStrings, stringLength, totalLength,
3970         // slotRawSymbol(&gCompilingClass->name)->name, slotRawSymbol(&gCompilingMethod->name)->name);
3971     }
3972 
3973     gCompilingBlock = prevBlock;
3974     gCompilingClass = prevClass;
3975     gPartiallyAppliedFunction = prevPartiallyAppliedFunction;
3976     gFunctionCantBeClosed = gFunctionCantBeClosed || prevFunctionCantBeClosed;
3977     gFunctionHighestExternalRef = sc_max(gFunctionHighestExternalRef - 1, prevFunctionHighestExternalRef);
3978 }
3979 
3980 
linkNextNode(PyrParseNode * a,PyrParseNode * b)3981 PyrParseNode* linkNextNode(PyrParseNode* a, PyrParseNode* b) {
3982     if (a == nullptr)
3983         return b;
3984     if (b) {
3985         a->mTail->mNext = b;
3986         a->mTail = b->mTail;
3987     }
3988     return a;
3989 }
3990 
linkAfterHead(PyrParseNode * a,PyrParseNode * b)3991 PyrParseNode* linkAfterHead(PyrParseNode* a, PyrParseNode* b) {
3992     b->mNext = a->mNext;
3993     if (!a->mNext)
3994         a->mTail = b;
3995     a->mNext = b;
3996     return a;
3997 }
3998 
isSuperObjNode(PyrParseNode * node)3999 bool isSuperObjNode(PyrParseNode* node) {
4000     return node->mClassno == pn_PushNameNode && slotRawSymbol(&((PyrPushNameNode*)node)->mSlot) == s_super;
4001 }
4002 
isThisObjNode(PyrParseNode * node)4003 bool isThisObjNode(PyrParseNode* node) {
4004     return node->mClassno == pn_PushNameNode && slotRawSymbol(&((PyrPushNameNode*)node)->mSlot) == s_this;
4005 }
4006 
nodeListLength(PyrParseNode * node)4007 int nodeListLength(PyrParseNode* node) {
4008     int length = 0;
4009     for (; node; node = node->mNext)
4010         length++;
4011     return length;
4012 }
4013 
4014 
conjureSelectorIndex(PyrParseNode * node,PyrBlock * func,bool isSuper,PyrSymbol * selector,int * selType)4015 int conjureSelectorIndex(PyrParseNode* node, PyrBlock* func, bool isSuper, PyrSymbol* selector, int* selType) {
4016     int i;
4017     PyrObject* selectors;
4018     PyrSlot* slot;
4019     int newsize, flags;
4020 
4021     flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
4022     if (!isSuper) {
4023         if (selector == gSpecialSelectors[opmIf]) {
4024             *selType = selIf;
4025             return opmIf;
4026         } else if (selector == gSpecialSelectors[opmWhile]) {
4027             *selType = selWhile;
4028             return opmWhile;
4029         } else if (selector == gSpecialSelectors[opmAnd]) {
4030             *selType = selAnd;
4031             return opmAnd;
4032         } else if (selector == gSpecialSelectors[opmOr]) {
4033             *selType = selOr;
4034             return opmOr;
4035         } else if (selector == gSpecialSelectors[opmCase]) {
4036             *selType = selCase;
4037             return opmCase;
4038         } else if (selector == gSpecialSelectors[opmSwitch]) {
4039             *selType = selSwitch;
4040             return opmSwitch;
4041         } else if (selector == gSpecialSelectors[opmLoop]) {
4042             *selType = selLoop;
4043             return opmLoop;
4044         } else if (selector == gSpecialSelectors[opmQuestionMark]) {
4045             *selType = selQuestionMark;
4046             return opmAnd;
4047         } else if (selector == gSpecialSelectors[opmDoubleQuestionMark]) {
4048             *selType = selDoubleQuestionMark;
4049             return opmAnd;
4050         } else if (selector == gSpecialSelectors[opmExclamationQuestionMark]) {
4051             *selType = selExclamationQuestionMark;
4052             return opmAnd;
4053         }
4054 
4055         for (i = 0; i < opmNumSpecialSelectors; ++i) {
4056             if (selector == gSpecialSelectors[i]) {
4057                 *selType = selSpecial;
4058                 return i;
4059             }
4060         }
4061 
4062         for (i = 0; i < opNumUnarySelectors; ++i) {
4063             if (selector == gSpecialUnarySelectors[i]) {
4064                 *selType = selUnary;
4065                 return i;
4066             }
4067         }
4068 
4069         for (i = 0; i < opNumBinarySelectors; ++i) {
4070             if (selector == gSpecialBinarySelectors[i]) {
4071                 *selType = selBinary;
4072                 return i;
4073             }
4074         }
4075     }
4076 
4077     if (NotNil(&func->selectors)) {
4078         selectors = slotRawObject(&func->selectors);
4079         for (i = 0; i < selectors->size; ++i) {
4080             if (IsSym(&selectors->slots[i]) && slotRawSymbol(&selectors->slots[i]) == selector) {
4081                 *selType = selNormal;
4082                 return i;
4083             }
4084         }
4085     } else {
4086         selectors = (PyrObject*)newPyrArray(compileGC(), 2, flags, false);
4087         SetObject(&func->selectors, selectors);
4088     }
4089     // otherwise add it to the selectors table
4090 
4091     if (selectors->size + 1 >= 256) {
4092         error("Selector table too big: too many classes, method selectors or function definitions in this function. "
4093               "Simplify the function.\n");
4094         post("Next selector was: %s\n", selector->name);
4095         nodePostErrorLine(node);
4096         compileErrors++;
4097         return 0;
4098     }
4099 
4100     if (selectors->size + 1 > ARRAYMAXINDEXSIZE(selectors)) {
4101         // resize literal table
4102         newsize = ARRAYMAXINDEXSIZE(selectors) * 2;
4103         SetRaw(&func->selectors, (PyrObject*)newPyrArray(compileGC(), newsize, flags, false));
4104         memcpy(slotRawObject(&func->selectors)->slots, selectors->slots, selectors->size * sizeof(PyrSlot));
4105         slotRawObject(&func->selectors)->size = selectors->size;
4106         freePyrObject(selectors);
4107         selectors = slotRawObject(&func->selectors);
4108     }
4109     slot = selectors->slots + selectors->size++;
4110     SetSymbol(slot, selector);
4111 
4112     *selType = selNormal;
4113     return selectors->size - 1;
4114 }
4115 
conjureLiteralSlotIndex(PyrParseNode * node,PyrBlock * func,PyrSlot * slot)4116 int conjureLiteralSlotIndex(PyrParseNode* node, PyrBlock* func, PyrSlot* slot) {
4117     int i;
4118     PyrObject* selectors;
4119     PyrSlot* slot2;
4120     int newsize, flags;
4121 
4122     flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
4123     // lookup slot in selectors table
4124 
4125     if (IsObj(&func->selectors)) {
4126         selectors = slotRawObject(&func->selectors);
4127         /*if (selectors->classptr != class_array) {
4128             post("compiling %s:%s\n", slotRawSymbol(&gCompilingClass->name)->name,
4129         slotRawSymbol(&gCompilingMethod->name)->name); post("selectors is a '%s'\n",
4130         selectors->classptr->name.us->name); dumpObjectSlot(slot); Debugger();
4131         }*/
4132         for (i = 0; i < selectors->size; ++i)
4133             if (SlotEq(&selectors->slots[i], slot))
4134                 return i;
4135     } else {
4136         selectors = (PyrObject*)newPyrArray(compileGC(), 4, flags, false);
4137         SetObject(&func->selectors, selectors);
4138     }
4139     // otherwise add it to the selectors table
4140 
4141     if (selectors->size + 1 >= 256) {
4142         error("Selector table too big: too many classes, method selectors or function definitions in this function. "
4143               "Simplify the function.\n");
4144         post("Next literal was:\n");
4145         dumpPyrSlot(slot);
4146         nodePostErrorLine(node);
4147         compileErrors++;
4148         return 0;
4149     }
4150     if (selectors->size + 1 > ARRAYMAXINDEXSIZE(selectors)) {
4151         // resize literal table
4152         newsize = ARRAYMAXINDEXSIZE(selectors) * 2;
4153         // resize literal table
4154         SetRaw(&func->selectors, (PyrObject*)newPyrArray(compileGC(), newsize, flags, false));
4155         memcpy(slotRawObject(&func->selectors)->slots, selectors->slots, selectors->size * sizeof(PyrSlot));
4156         slotRawObject(&func->selectors)->size = selectors->size;
4157         freePyrObject(selectors);
4158         selectors = slotRawObject(&func->selectors);
4159     }
4160     slot2 = selectors->slots + selectors->size++;
4161     slotCopy(slot2, slot);
4162 
4163     return selectors->size - 1;
4164 }
4165 
4166 
conjureConstantIndex(PyrParseNode * node,PyrBlock * func,PyrSlot * slot)4167 int conjureConstantIndex(PyrParseNode* node, PyrBlock* func, PyrSlot* slot) {
4168     int i;
4169     PyrObject* constants;
4170     int newsize, flags;
4171 
4172     flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
4173 
4174     // lookup slot in constants table
4175     if (IsObj(&func->constants)) {
4176         constants = slotRawObject(&func->constants);
4177         for (i = 0; i < constants->size; ++i)
4178             if (SlotEq(&constants->slots[i], slot))
4179                 return i;
4180     } else {
4181         constants = (PyrObject*)newPyrArray(compileGC(), 4, flags, false);
4182         SetObject(&func->constants, constants);
4183     }
4184 
4185     // otherwise add it to the constants table
4186     if (constants->size + 1 > ARRAYMAXINDEXSIZE(constants)) {
4187         // resize literal table
4188         newsize = ARRAYMAXINDEXSIZE(constants) * 2;
4189         // resize literal table
4190         SetRaw(&func->constants, (PyrObject*)newPyrArray(compileGC(), newsize, flags, false));
4191         memcpy(slotRawObject(&func->constants)->slots, constants->slots, constants->size * sizeof(PyrSlot));
4192         slotRawObject(&func->constants)->size = constants->size;
4193         freePyrObject((PyrObject*)constants);
4194         constants = slotRawObject(&func->constants);
4195     }
4196     slotCopy(&constants->slots[constants->size++], slot);
4197 
4198     return constants->size - 1;
4199 }
4200 
findVarName(PyrBlock * func,PyrClass ** classobj,PyrSymbol * name,int * varType,int * level,int * index,PyrBlock ** tempfunc)4201 bool findVarName(PyrBlock* func, PyrClass** classobj, PyrSymbol* name, int* varType, int* level, int* index,
4202                  PyrBlock** tempfunc) {
4203     int i, j, k;
4204     int numargs;
4205     PyrSymbol *argname, *varname;
4206     PyrMethodRaw* methraw;
4207 
4208     // postfl("->findVarName %s\n", name->name);
4209     // find var in enclosing blocks, instance, class
4210     if (name == s_super) {
4211         gFunctionCantBeClosed = true;
4212         name = s_this;
4213     }
4214     if (name->name[0] >= 'A' && name->name[0] <= 'Z')
4215         return false;
4216     for (j = 0; func; func = slotRawBlock(&func->contextDef), ++j) {
4217         methraw = METHRAW(func);
4218         numargs = methraw->posargs;
4219         for (i = 0; i < numargs; ++i) {
4220             argname = slotRawSymbolArray(&func->argNames)->symbols[i];
4221             // postfl("    %d %d arg '%s' '%s'\n", j, i, argname->name, name->name);
4222             if (argname == name) {
4223                 *level = j;
4224                 *index = i;
4225                 *varType = varTemp;
4226                 if (tempfunc)
4227                     *tempfunc = func;
4228                 if (j > gFunctionHighestExternalRef)
4229                     gFunctionHighestExternalRef = j;
4230                 return true;
4231             }
4232         }
4233         for (i = 0, k = numargs; i < methraw->numvars; ++i, ++k) {
4234             varname = slotRawSymbolArray(&func->varNames)->symbols[i];
4235             // postfl("    %d %d %d var '%s' '%s'\n", j, i, k, varname->name, name->name);
4236             if (varname == name) {
4237                 *level = j;
4238                 *index = k;
4239                 *varType = varTemp;
4240                 if (tempfunc)
4241                     *tempfunc = func;
4242                 if (j > gFunctionHighestExternalRef)
4243                     gFunctionHighestExternalRef = j;
4244                 return true;
4245             }
4246         }
4247     }
4248 
4249     if (classFindInstVar(*classobj, name, index)) {
4250         *level = 0;
4251         *varType = varInst;
4252         if (gCompilingClass != class_interpreter)
4253             gFunctionCantBeClosed = true;
4254         return true;
4255     }
4256     if (classFindClassVar(classobj, name, index)) {
4257         *varType = varClass;
4258         if (gCompilingClass != class_interpreter)
4259             gFunctionCantBeClosed = true;
4260         return true;
4261     }
4262     if (classFindConst(classobj, name, index)) {
4263         *varType = varConst;
4264         // if (gCompilingClass != class_interpreter) gFunctionCantBeClosed = true;
4265         return true;
4266     }
4267     if (name == s_curProcess) {
4268         *varType = varPseudo;
4269         *index = opgProcess;
4270         return true;
4271     }
4272     if (name == s_curThread) {
4273         *varType = varPseudo;
4274         *index = opgThread;
4275         return true;
4276     }
4277     if (name == s_curMethod) {
4278         *varType = varPseudo;
4279         *index = opgMethod;
4280         return true;
4281     }
4282     if (name == s_curBlock) {
4283         *varType = varPseudo;
4284         *index = opgFunctionDef;
4285         return true;
4286     }
4287     if (name == s_curClosure) {
4288         *varType = varPseudo;
4289         *index = opgFunction;
4290         return true;
4291     }
4292     return false;
4293 }
4294 
4295 extern PyrSymbol* s_env;
4296 
initSpecialClasses()4297 void initSpecialClasses() {
4298     gSpecialClasses[op_class_object] = s_object;
4299     gSpecialClasses[op_class_symbol] = s_symbol;
4300     gSpecialClasses[op_class_nil] = s_nil;
4301     gSpecialClasses[op_class_boolean] = s_boolean;
4302     gSpecialClasses[op_class_true] = s_true;
4303     gSpecialClasses[op_class_false] = s_false;
4304     gSpecialClasses[op_class_magnitude] = s_magnitude;
4305     gSpecialClasses[op_class_char] = s_char;
4306     gSpecialClasses[op_class_number] = s_number;
4307     gSpecialClasses[op_class_complex] = s_complex;
4308     gSpecialClasses[op_class_simple_number] = s_simple_number;
4309     gSpecialClasses[op_class_int] = s_int;
4310     gSpecialClasses[op_class_float] = s_float;
4311     gSpecialClasses[op_class_method] = s_method;
4312     gSpecialClasses[op_class_fundef] = s_fundef;
4313     gSpecialClasses[op_class_stream] = s_stream;
4314     gSpecialClasses[op_class_func] = s_func;
4315     gSpecialClasses[op_class_frame] = s_frame;
4316     gSpecialClasses[op_class_process] = s_process;
4317     gSpecialClasses[op_class_main] = s_main;
4318     gSpecialClasses[op_class_class] = s_class;
4319     gSpecialClasses[op_class_string] = s_string;
4320 
4321     gSpecialClasses[op_class_collection] = s_collection;
4322     gSpecialClasses[op_class_sequenceable_collection] = s_sequenceable_collection;
4323     gSpecialClasses[op_class_arrayed_collection] = s_arrayed_collection;
4324     gSpecialClasses[op_class_array] = s_array;
4325     gSpecialClasses[op_class_int8array] = s_int8array;
4326     gSpecialClasses[op_class_int16array] = s_int16array;
4327     gSpecialClasses[op_class_int32array] = s_int32array;
4328     gSpecialClasses[op_class_floatarray] = s_floatarray;
4329     gSpecialClasses[op_class_signal] = s_signal;
4330     gSpecialClasses[op_class_doublearray] = s_doublearray;
4331     gSpecialClasses[op_class_symbolarray] = s_symbolarray;
4332     gSpecialClasses[op_class_list] = s_list;
4333     gSpecialClasses[op_class_linkedlist] = s_linkedlist;
4334     gSpecialClasses[op_class_bag] = s_bag;
4335     gSpecialClasses[op_class_set] = s_set;
4336     gSpecialClasses[op_class_identityset] = s_identityset;
4337     gSpecialClasses[op_class_dictionary] = s_dictionary;
4338     gSpecialClasses[op_class_identitydictionary] = s_identitydictionary;
4339     gSpecialClasses[op_class_sortedlist] = s_sortedlist;
4340 
4341     gSpecialClasses[op_class_synth] = s_synth;
4342     gSpecialClasses[op_class_ref] = s_ref;
4343     gSpecialClasses[op_class_environment] = s_environment;
4344     gSpecialClasses[op_class_event] = s_event;
4345     gSpecialClasses[op_class_wavetable] = s_wavetable;
4346     gSpecialClasses[op_class_env] = s_env;
4347     gSpecialClasses[op_class_routine] = s_routine;
4348     gSpecialClasses[op_class_color] = s_color;
4349     gSpecialClasses[op_class_rect] = s_rect;
4350 
4351     // Infinitum, Point, Rect, ??
4352 }
4353 
initSpecialSelectors()4354 void initSpecialSelectors() {
4355     PyrSymbol** sel;
4356     long i;
4357 
4358     sel = gSpecialUnarySelectors;
4359     sel[opNeg] = getsym("neg");
4360     sel[opRecip] = getsym("reciprocal");
4361     sel[opNot] = getsym("not");
4362     sel[opIsNil] = getsym("isNil");
4363     sel[opNotNil] = getsym("notNil");
4364     sel[opBitNot] = getsym("bitNot");
4365     sel[opAbs] = getsym("abs");
4366     sel[opAsFloat] = getsym("asFloat");
4367     sel[opAsInteger] = getsym("asInteger");
4368     sel[opCeil] = getsym("ceil"); // 5
4369     sel[opFloor] = getsym("floor");
4370     sel[opFrac] = getsym("frac");
4371     sel[opSign] = getsym("sign");
4372     sel[opSquared] = getsym("squared");
4373     sel[opCubed] = getsym("cubed"); // 10
4374     sel[opSqrt] = getsym("sqrt");
4375     sel[opExp] = getsym("exp");
4376     sel[opMIDICPS] = getsym("midicps");
4377     sel[opCPSMIDI] = getsym("cpsmidi");
4378     sel[opMIDIRatio] = getsym("midiratio");
4379     sel[opRatioMIDI] = getsym("ratiomidi");
4380     sel[opAmpDb] = getsym("ampdb"); // 15
4381     sel[opDbAmp] = getsym("dbamp");
4382     sel[opOctCPS] = getsym("octcps");
4383     sel[opCPSOct] = getsym("cpsoct");
4384     sel[opLog] = getsym("log");
4385     sel[opLog2] = getsym("log2"); // 20
4386     sel[opLog10] = getsym("log10");
4387     sel[opSin] = getsym("sin");
4388     sel[opCos] = getsym("cos");
4389     sel[opTan] = getsym("tan");
4390     sel[opArcSin] = getsym("asin"); // 25
4391     sel[opArcCos] = getsym("acos");
4392     sel[opArcTan] = getsym("atan");
4393     sel[opSinH] = getsym("sinh");
4394     sel[opCosH] = getsym("cosh");
4395     sel[opTanH] = getsym("tanh"); // 30
4396     sel[opRand] = getsym("rand");
4397     sel[opRand2] = getsym("rand2");
4398     sel[opLinRand] = getsym("linrand");
4399     sel[opBiLinRand] = getsym("bilinrand");
4400     sel[opSum3Rand] = getsym("sum3rand");
4401     /*
4402         sel[opExpRand] = getsym("exprand");
4403         sel[opBiExpRand] = getsym("biexprand");
4404         sel[opGammaRand] = getsym("gammarand");
4405         sel[opGaussRand] = getsym("gaussrand");
4406         sel[opPoiRand] = getsym("poirand");
4407     */
4408     sel[opDistort] = getsym("distort");
4409     sel[opSoftClip] = getsym("softclip");
4410     sel[opCoin] = getsym("coin");
4411 
4412     sel[opRectWindow] = getsym("rectWindow");
4413     sel[opHanWindow] = getsym("hanWindow");
4414     sel[opWelchWindow] = getsym("welWindow");
4415     sel[opTriWindow] = getsym("triWindow");
4416 
4417     sel[opSCurve] = getsym("scurve");
4418     sel[opRamp] = getsym("ramp");
4419 
4420     sel[opDigitValue] = getsym("digitValue");
4421     sel[opSilence] = getsym("silence");
4422     sel[opThru] = getsym("thru");
4423 
4424 
4425     sel = gSpecialBinarySelectors;
4426 
4427     sel[opAdd] = getsym("+");
4428     sel[opSub] = getsym("-");
4429     sel[opMul] = getsym("*");
4430 
4431     sel[opFDiv] = getsym("/");
4432     sel[opIDiv] = getsym("div");
4433     sel[opMod] = getsym("mod");
4434     sel[opEQ] = getsym("==");
4435     sel[opNE] = getsym("!=");
4436     sel[opLT] = getsym("<");
4437     sel[opGT] = getsym(">");
4438     sel[opLE] = getsym("<=");
4439     sel[opGE] = getsym(">=");
4440     // sel[opIdentical] = getsym("===");
4441     // sel[opNotIdentical] = getsym("!==");
4442     sel[opMin] = getsym("min");
4443     sel[opMax] = getsym("max");
4444     sel[opBitAnd] = getsym("bitAnd");
4445     sel[opBitOr] = getsym("bitOr");
4446     sel[opBitXor] = getsym("bitXor");
4447     sel[opLCM] = getsym("lcm");
4448     sel[opGCD] = getsym("gcd");
4449     sel[opRound] = getsym("round");
4450     sel[opRoundUp] = getsym("roundUp");
4451     sel[opTrunc] = getsym("trunc");
4452     sel[opAtan2] = getsym("atan2");
4453     sel[opHypot] = getsym("hypot");
4454     sel[opHypotx] = getsym("hypotApx");
4455     sel[opPow] = getsym("pow");
4456     sel[opShiftLeft] = getsym("leftShift");
4457     sel[opShiftRight] = getsym("rightShift");
4458     sel[opUnsignedShift] = getsym("unsignedRightShift");
4459     sel[opFill] = getsym("fill");
4460     sel[opRing1] = getsym("ring1"); // a * (b + 1) == a * b + a
4461     sel[opRing2] = getsym("ring2"); // a * b + a + b
4462     sel[opRing3] = getsym("ring3"); // a*a*b
4463     sel[opRing4] = getsym("ring4"); // a*a*b - a*b*b
4464     sel[opDifSqr] = getsym("difsqr"); // a*a - b*b
4465     sel[opSumSqr] = getsym("sumsqr"); // a*a + b*b
4466     sel[opSqrSum] = getsym("sqrsum"); // (a + b)^2
4467     sel[opSqrDif] = getsym("sqrdif"); // (a - b)^2
4468     sel[opAbsDif] = getsym("absdif"); //
4469     sel[opThresh] = getsym("thresh"); //
4470     sel[opAMClip] = getsym("amclip"); //
4471     sel[opScaleNeg] = getsym("scaleneg"); //
4472     sel[opClip2] = getsym("clip2");
4473     sel[opFold2] = getsym("fold2");
4474     sel[opWrap2] = getsym("wrap2");
4475     sel[opExcess] = getsym("excess");
4476     sel[opFirstArg] = getsym("firstArg");
4477     sel[opRandRange] = getsym("rrand");
4478     sel[opExpRandRange] = getsym("exprand");
4479 
4480 
4481     sel = gSpecialSelectors;
4482 
4483     sel[opmNew] = getsym("new");
4484     sel[opmNewClear] = getsym("newClear");
4485     sel[opmNewCopyArgs] = getsym("newCopyArgs");
4486     sel[opmInit] = getsym("init");
4487     sel[opmAt] = getsym("at");
4488     sel[opmPut] = getsym("put");
4489     sel[opmNext] = getsym("next");
4490     sel[opmReset] = getsym("reset");
4491     sel[opmValue] = getsym("value");
4492     sel[opmCopyToEnd] = getsym("copyToEnd"); // used by multiple assignment
4493     // sel[opmIsNil] = getsym("isNil");
4494     // sel[opmNotNil] = getsym("notNil");
4495     sel[opmSize] = getsym("size");
4496     sel[opmClass] = getsym("class");
4497     sel[opmIf] = getsym("if");
4498     sel[opmWhile] = getsym("while");
4499     sel[opmFor] = getsym("for");
4500     sel[opmAnd] = getsym("and");
4501     sel[opmOr] = getsym("or");
4502     sel[opmCase] = getsym("case");
4503     sel[opmSwitch] = getsym("switch");
4504     sel[opmIdentical] = getsym("===");
4505     sel[opmNotIdentical] = getsym("!==");
4506 
4507     sel[opmPrint] = getsym("print");
4508     sel[opmAdd] = getsym("add");
4509     sel[opmRemove] = getsym("remove");
4510     sel[opmIndexOf] = getsym("indexOf");
4511     sel[opmWrapAt] = getsym("wrapAt");
4512     sel[opmClipAt] = getsym("clipAt");
4513     sel[opmFoldAt] = getsym("foldAt");
4514     sel[opmWrapPut] = getsym("wrapPut");
4515     sel[opmClipPut] = getsym("clipPut");
4516     sel[opmFoldPut] = getsym("foldPut");
4517     sel[opmDo] = getsym("do");
4518     sel[opmCollect] = getsym("collect");
4519     sel[opmSelect] = getsym("select");
4520     sel[opmReject] = getsym("reject");
4521     sel[opmAny] = getsym("any");
4522     sel[opmEvery] = getsym("every");
4523     sel[opmFind] = getsym("find");
4524 
4525     sel[opmChoose] = getsym("choose");
4526 
4527     sel[opmValueList] = getsym("valueList");
4528     sel[opmAddFirst] = getsym("addFirst");
4529 
4530     sel[opmPrimitiveFailed] = getsym("primitiveFailed");
4531     sel[opmSubclassResponsibility] = getsym("subclassResponsibility");
4532     sel[opmShouldNotImplement] = getsym("shouldNotImplement");
4533     sel[opmDoesNotUnderstand] = getsym("doesNotUnderstand"); // not really needed
4534     sel[opmNotYetImplemented] = getsym("notYetImplemented");
4535 
4536     sel[opmAtSign] = getsym("@");
4537     sel[opmWrapAtSign] = getsym("@@");
4538     sel[opmClipAtSign] = getsym("|@|");
4539     sel[opmFoldAtSign] = getsym("@|@");
4540 
4541     sel[opmMultiNew] = getsym("multiNew"); // UGens
4542     sel[opmMultiNewList] = getsym("multiNewList"); // UGens
4543     sel[opmAR] = getsym("ar"); // UGens
4544     sel[opmKR] = getsym("kr"); // UGens
4545     sel[opmIR] = getsym("ir"); // UGens
4546 
4547     sel[opmEnvirGet] = getsym("envirGet");
4548     sel[opmEnvirPut] = getsym("envirPut");
4549 
4550     sel[opmHalt] = getsym("halt");
4551     sel[opmForBy] = getsym("forBy");
4552     sel[opmForSeries] = getsym("forSeries");
4553     sel[opmReverseDo] = getsym("reverseDo");
4554     sel[opmLoop] = getsym("loop");
4555     sel[opmNonBooleanError] = getsym("mustBeBoolean");
4556 
4557     sel[opmCopy] = getsym("copy");
4558     sel[opmPerformList] = getsym("performList");
4559     sel[opmIsKindOf] = getsym("isKindOf");
4560     sel[opmPostln] = getsym("postln");
4561     sel[opmAsString] = getsym("asString");
4562 
4563     sel[opmPlusPlus] = getsym("++");
4564     sel[opmLTLT] = getsym("<<");
4565     sel[opmQuestionMark] = getsym("?");
4566     sel[opmDoubleQuestionMark] = getsym("??");
4567     sel[opmExclamationQuestionMark] = getsym("!?");
4568 
4569     sel[opmYield] = getsym("yield");
4570     sel[opmName] = getsym("name");
4571     sel[opmMulAdd] = getsym("madd");
4572 
4573     sel[opmSeries] = getsym("series");
4574 
4575     for (i = 0; i < opNumUnarySelectors; ++i) {
4576         gSpecialUnarySelectors[i]->specialIndex = i;
4577     }
4578     for (i = 0; i < opNumBinarySelectors; ++i) {
4579         gSpecialBinarySelectors[i]->specialIndex = i;
4580     }
4581 }
4582 
findSpecialClassName(PyrSymbol * className,int * index)4583 bool findSpecialClassName(PyrSymbol* className, int* index) {
4584     int i;
4585     for (i = 0; i < op_NumSpecialClasses; ++i) {
4586         if (gSpecialClasses[i] == className) {
4587             *index = i;
4588             return true;
4589         }
4590     }
4591     return false;
4592 }
4593