1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
5 Copyright (c) 2017 Brian Heim (boost::filesystem additions)
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <float.h>
25 #include <math.h>
26 #include <new>
27 #include <stdlib.h>
28 #include <ctype.h>
29 #include <cerrno>
30 #include <limits>
31 #include <set>
32
33 #ifdef _WIN32
34 # include <direct.h>
35 #else
36 # include <sys/param.h>
37 #endif
38
39 #include <boost/filesystem/path.hpp>
40 #include <boost/filesystem/operations.hpp>
41 #include <boost/filesystem/string_file.hpp>
42
43 #include "PyrParseNode.h"
44 #include "Bison/lang11d_tab.h"
45 #include "SCBase.h"
46 #include "PyrObject.h"
47 #include "PyrObjectProto.h"
48 #include "PyrLexer.h"
49 #include "PyrSched.h"
50 #include "SC_InlineUnaryOp.h"
51 #include "SC_InlineBinaryOp.h"
52 #include "GC.h"
53 #include "SimpleStack.h"
54
55 #include "PyrSymbolTable.h"
56 #include "PyrInterpreter.h"
57 #include "PyrPrimitive.h"
58 #include "PyrObjectProto.h"
59 #include "PyrPrimitiveProto.h"
60 #include "PyrKernelProto.h"
61 #include "InitAlloc.h"
62 #include "PredefinedSymbols.h"
63 #ifdef _WIN32
64 #else
65 # include "dirent.h"
66 #endif
67 #include <string.h>
68
69 #include "SC_LanguageConfig.hpp"
70
71 #include "SC_Filesystem.hpp" // getDirectory, resolveIfAlias, isStandalone
72 #include "SC_Codecvt.hpp" // path_to_utf8_str
73 #include "SC_TextUtils.hpp"
74
75 int yyparse();
76 int processaccidental1(char* s);
77 int processaccidental2(char* s);
78
79
80 extern bool gFullyFunctional;
81 double compileStartTime;
82 int gNumCompiledFiles;
83 /*
84 thisProcess.interpreter.executeFile("Macintosh HD:score").size.postln;
85 */
86
87 namespace bfs = boost::filesystem;
88 using DirName = SC_Filesystem::DirName;
89
90 PyrSymbol* gCompilingFileSym = nullptr;
91 VMGlobals* gCompilingVMGlobals = nullptr;
92 static bfs::path gCompileDir;
93
94 //#define DEBUGLEX 1
95 bool gDebugLexer = false;
96
97 bool gShowWarnings = false;
98 LongStack brackets;
99 LongStack closedFuncCharNo;
100 LongStack generatorStack;
101 int lastClosedFuncCharNo = 0;
102
103 const char* binopchars = "!@%&*-+=|<>?/";
104 char yytext[MAXYYLEN];
105 bfs::path currfilename;
106 std::string printingCurrfilename; // for error reporting
107
108 int yylen;
109 int lexCmdLine = 0;
110 bool compilingCmdLine = false;
111 bool compilingCmdLineErrorWindow = false;
112
113 intptr_t zzval;
114
115 int lineno, charno, linepos;
116 int* linestarts;
117 int maxlinestarts;
118
119 char* text;
120 int textlen;
121 int textpos;
122 int errLineOffset, errCharPosOffset;
123 int parseFailed = 0;
124 bool compiledOK = false;
125 std::set<bfs::path> compiledDirectories;
126
127 /* so the text editor's dumb paren matching will work */
128 #define OPENPAREN '('
129 #define OPENCURLY '{'
130 #define OPENSQUAR '['
131 #define CLOSSQUAR ']'
132 #define CLOSCURLY '}'
133 #define CLOSPAREN ')'
134
sc_strtoi(const char * str,int n,int base)135 int sc_strtoi(const char* str, int n, int base) {
136 int z = 0;
137 for (int i = 0; i < n; ++i) {
138 int c = *str++;
139 if (!c)
140 break;
141 if (c >= '0' && c <= '0' + sc_min(10, base) - 1)
142 z = z * base + c - '0';
143 else if (c >= 'a' && c <= 'a' + sc_min(36, base) - 11)
144 z = z * base + c - 'a' + 10;
145 else if (c >= 'A' && c <= 'A' + sc_min(36, base) - 11)
146 z = z * base + c - 'A' + 10;
147 }
148 return z;
149 }
150
sc_strtof(const char * str,int n,int base)151 double sc_strtof(const char* str, int n, int base) {
152 double z = 0.;
153 int decptpos = 0;
154 for (int i = 0; i < n; ++i) {
155 int c = *str++;
156 if (!c)
157 break;
158 if (c >= '0' && c <= '0' + sc_min(10, base) - 1)
159 z = z * base + c - '0';
160 else if (c >= 'a' && c <= 'a' + sc_min(36, base) - 11)
161 z = z * base + c - 'a' + 10;
162 else if (c >= 'A' && c <= 'A' + sc_min(36, base) - 11)
163 z = z * base + c - 'A' + 10;
164 else if (c == '.')
165 decptpos = i;
166 }
167 // calculation previously included decimal point in count of columns (was n-decptpos); there are 1 less than n
168 // characters which are columns in the number contribution
169 z = z / pow((double)base, n - 1 - decptpos);
170 return z;
171 }
172
173 bool startLexer(PyrSymbol* fileSym, const bfs::path& p, int startPos, int endPos, int lineOffset);
startLexer(PyrSymbol * fileSym,const bfs::path & p,int startPos,int endPos,int lineOffset)174 bool startLexer(PyrSymbol* fileSym, const bfs::path& p, int startPos, int endPos, int lineOffset) {
175 const char* filename = fileSym->name;
176
177 textlen = -1;
178
179 if (!fileSym->u.source) {
180 try {
181 bfs::ifstream file;
182 file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
183 file.open(p, std::ios_base::binary);
184 size_t sz = bfs::file_size(p);
185
186 text = (char*)pyr_pool_compile->Alloc((sz + 1) * sizeof(char));
187 file.read(text, sz);
188 text[sz] = '\0';
189 fileSym->u.source = text;
190 rtf2txt(text);
191 } catch (const std::exception& ex) {
192 error("Could not read %s: %s.\n", SC_Codecvt::path_to_utf8_str(p).c_str(), ex.what());
193 return false;
194 }
195 } else
196 text = fileSym->u.source;
197
198 if ((startPos >= 0) && (endPos > 0)) {
199 textlen = endPos - startPos;
200 text += startPos;
201 } else if (textlen == -1)
202 textlen = strlen(text);
203
204 if (lineOffset > 0)
205 errLineOffset = lineOffset;
206 else
207 errLineOffset = 0;
208
209 if (startPos > 0)
210 errCharPosOffset = startPos;
211 else
212 errCharPosOffset = 0;
213
214 initLongStack(&brackets);
215 initLongStack(&closedFuncCharNo);
216 initLongStack(&generatorStack);
217 lastClosedFuncCharNo = 0;
218 textpos = 0;
219 linepos = 0;
220 lineno = 1;
221 charno = 0;
222
223 yylen = 0;
224 zzval = 0;
225 parseFailed = 0;
226 lexCmdLine = 0;
227 currfilename = bfs::path(filename);
228 printingCurrfilename = "file '" + SC_Codecvt::path_to_utf8_str(currfilename) + "'";
229 maxlinestarts = 1000;
230 linestarts = (int*)pyr_pool_compile->Alloc(maxlinestarts * sizeof(int*));
231 linestarts[0] = 0;
232 linestarts[1] = 0;
233
234 return true;
235 }
236
startLexerCmdLine(char * textbuf,int textbuflen)237 void startLexerCmdLine(char* textbuf, int textbuflen) {
238 // pyrmalloc:
239 // lifetime: kill after compile. (this one gets killed anyway)
240 text = (char*)pyr_pool_compile->Alloc((textbuflen + 2) * sizeof(char));
241 MEMFAIL(text);
242 memcpy(text, textbuf, textbuflen);
243 text[textbuflen] = ' ';
244 text[textbuflen + 1] = 0;
245 textlen = textbuflen + 1;
246
247 rtf2txt(text);
248
249 initLongStack(&brackets);
250 initLongStack(&closedFuncCharNo);
251 initLongStack(&generatorStack);
252 lastClosedFuncCharNo = 0;
253 textpos = 0;
254 linepos = 0;
255 lineno = 1;
256 charno = 0;
257
258 yylen = 0;
259 zzval = 0;
260 parseFailed = 0;
261 lexCmdLine = 1;
262 currfilename = bfs::path("interpreted text");
263 printingCurrfilename = currfilename.string();
264 maxlinestarts = 1000;
265 linestarts = (int*)pyr_pool_compile->Alloc(maxlinestarts * sizeof(int*));
266 linestarts[0] = 0;
267 linestarts[1] = 0;
268
269 errLineOffset = 0;
270 errCharPosOffset = 0;
271 }
272
finiLexer()273 void finiLexer() {
274 pyr_pool_compile->Free(linestarts);
275 freeLongStack(&brackets);
276 freeLongStack(&closedFuncCharNo);
277 freeLongStack(&generatorStack);
278 }
279
initLexer()280 void initLexer() {
281 // strcpy(binopchars, "!@%&*-+=|:<>?/");
282 }
283
input()284 int input() {
285 int c;
286 if (textpos >= textlen) {
287 c = 0;
288 } else {
289 c = text[textpos++];
290 charno++;
291 }
292 if (c == '\n' || c == '\r') {
293 lineno++;
294 linepos = textpos;
295 if (linestarts) {
296 if (lineno >= maxlinestarts) {
297 maxlinestarts += maxlinestarts;
298 linestarts = (int*)pyr_pool_compile->Realloc(linestarts, maxlinestarts * sizeof(int*));
299 }
300 linestarts[lineno] = linepos;
301 }
302 charno = 0;
303 }
304 if (c != 0 && yylen < MAXYYLEN - 2)
305 yytext[yylen++] = c;
306 // if (gDebugLexer) postfl("input '%c' %d\n",c,c);
307 return c;
308 }
309
input0()310 int input0() {
311 int c;
312 if (textpos >= textlen) {
313 c = 0;
314 textpos++; // so unput will work properly
315 } else {
316 c = text[textpos++];
317 charno++;
318 }
319 if (c == '\n' || c == '\r') {
320 lineno++;
321 linepos = textpos;
322 if (linestarts) {
323 if (lineno >= maxlinestarts) {
324 maxlinestarts += maxlinestarts;
325 linestarts = (int*)pyr_pool_compile->Realloc(linestarts, maxlinestarts * sizeof(int*));
326 }
327 linestarts[lineno] = linepos;
328 }
329 charno = 0;
330 }
331 // if (gDebugLexer) postfl("input0 '%c' %d\n",c,c);
332 return c;
333 }
334
unput(int c)335 void unput(int c) {
336 if (textpos > 0)
337 textpos--;
338 if (c) {
339 if (yylen)
340 --yylen;
341 if (charno)
342 --charno;
343 if (c == '\n' || c == '\r') {
344 --lineno;
345 }
346 }
347 }
348
unput0(int c)349 void unput0(int c) {
350 if (textpos > 0)
351 textpos--;
352 if (charno)
353 --charno;
354 if (c == '\n' || c == '\r') {
355 --lineno;
356 }
357 }
358
yylex()359 int yylex() {
360 int r, c, c2;
361 intptr_t d;
362 int radix;
363
364 yylen = 0;
365 // finite state machine to parse input stream into tokens
366
367 if (lexCmdLine == 1) {
368 lexCmdLine = 2;
369 r = INTERPRET;
370 goto leave;
371 }
372 start:
373 c = input();
374
375 if (c == 0) {
376 r = 0;
377 goto leave;
378 } else if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f') {
379 yylen = 0;
380 goto start;
381 } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
382 goto ident;
383 else if (c == '/') {
384 c = input();
385 if (c == '/')
386 goto comment1;
387 else if (c == '*')
388 goto comment2;
389 else {
390 unput(c);
391 goto binop;
392 }
393 } else if (c >= '0' && c <= '9')
394 goto digits_1;
395 else if (c == OPENPAREN || c == OPENSQUAR || c == OPENCURLY) {
396 pushls(&brackets, (intptr_t)c);
397 if (c == OPENCURLY) {
398 pushls(&closedFuncCharNo, (intptr_t)(linestarts[lineno] + charno - 1));
399 }
400 r = c;
401 goto leave;
402 } else if (c == CLOSSQUAR) {
403 if (!emptyls(&brackets)) {
404 if ((d = popls(&brackets)) != (intptr_t)OPENSQUAR) {
405 fatal();
406 post("opening bracket was a '%c', but found a '%c'\n", d, c);
407 goto error2;
408 }
409 } else {
410 fatal();
411 post("unmatched '%c'\n", c);
412 goto error2;
413 }
414 r = c;
415 goto leave;
416 } else if (c == CLOSPAREN) {
417 if (!emptyls(&brackets)) {
418 if ((d = popls(&brackets)) != OPENPAREN) {
419 fatal();
420 post("opening bracket was a '%c', but found a '%c'\n", d, c);
421 goto error2;
422 }
423 } else {
424 fatal();
425 post("unmatched '%c'\n", c);
426 goto error2;
427 }
428 r = c;
429 goto leave;
430 } else if (c == CLOSCURLY) {
431 if (!emptyls(&brackets)) {
432 if ((d = popls(&brackets)) != OPENCURLY) {
433 fatal();
434 post("opening bracket was a '%c', but found a '%c'\n", d, c);
435 goto error2;
436 }
437 lastClosedFuncCharNo = popls(&closedFuncCharNo);
438 } else {
439 fatal();
440 post("unmatched '%c'\n", c);
441 goto error2;
442 }
443 r = c;
444 goto leave;
445 } else if (c == '^') {
446 r = c;
447 goto leave;
448 } else if (c == '~') {
449 r = c;
450 goto leave;
451 } else if (c == ';') {
452 r = c;
453 goto leave;
454 } else if (c == ':') {
455 r = c;
456 goto leave;
457 } else if (c == '`') {
458 r = c;
459 goto leave;
460 } else if (c == '\\')
461 goto symbol1;
462 else if (c == '\'')
463 goto symbol3;
464 else if (c == '"')
465 goto string1;
466 else if (c == '.') {
467 if ((c = input()) == '.') {
468 if ((c = input()) == '.') {
469 r = ELLIPSIS;
470 goto leave;
471 } else {
472 r = DOTDOT;
473 unput(c);
474 goto leave;
475 }
476 } else {
477 unput(c);
478 r = '.';
479 goto leave;
480 }
481
482 } else if (c == '#') {
483 if ((c = input()) == OPENCURLY) {
484 pushls(&brackets, (intptr_t)OPENCURLY);
485 pushls(&closedFuncCharNo, (intptr_t)(linestarts[lineno] + charno - 2));
486 r = BEGINCLOSEDFUNC;
487 } else {
488 unput(c);
489 r = '#';
490 }
491 goto leave;
492 } else if (c == '$') {
493 c = input();
494 if (c == '\\') {
495 c = input();
496 switch (c) {
497 case 'n':
498 c = '\n';
499 break;
500 case 'r':
501 c = '\r';
502 break;
503 case 't':
504 c = '\t';
505 break;
506 case 'f':
507 c = '\f';
508 break;
509 case 'v':
510 c = '\v';
511 break;
512 }
513 }
514 r = processchar(c);
515 goto leave;
516 } else if (c == ',') {
517 r = c;
518 goto leave;
519 } else if (c == '=') {
520 c = input();
521 if (strchr(binopchars, c))
522 goto binop;
523 else {
524 unput(c);
525 r = '=';
526 goto leave;
527 }
528 } else if (strchr(binopchars, c))
529 goto binop;
530 else if (!(isprint(c) || isspace(c) || c == 0)) {
531 yylen = 0;
532 goto start;
533 } else
534 goto error1;
535
536 ident:
537 c = input();
538
539 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9'))
540 goto ident;
541 else if (c == ':') {
542 yytext[yylen] = 0;
543 r = processkeywordbinop(yytext);
544 goto leave;
545 } else {
546 unput(c);
547 yytext[yylen] = 0;
548 r = processident(yytext);
549 goto leave;
550 }
551
552 symbol1:
553 c = input();
554
555 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_')
556 goto symbol2;
557 else if (c >= '0' && c <= '9')
558 goto symbol4;
559 else {
560 unput(c);
561 yytext[yylen] = 0;
562 r = processsymbol(yytext);
563 goto leave;
564 }
565
566 symbol2:
567 c = input();
568
569 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_' || (c >= '0' && c <= '9'))
570 goto symbol2;
571 else {
572 unput(c);
573 yytext[yylen] = 0;
574 r = processsymbol(yytext);
575 goto leave;
576 }
577
578 symbol4:
579 c = input();
580 if (c >= '0' && c <= '9')
581 goto symbol4;
582 else {
583 unput(c);
584 yytext[yylen] = 0;
585 r = processsymbol(yytext);
586 goto leave;
587 }
588
589
590 binop:
591
592 c = input();
593
594 if (c == 0)
595 goto binop2;
596 if (strchr(binopchars, c))
597 goto binop;
598 else {
599 binop2:
600 unput(c);
601 yytext[yylen] = 0;
602 r = processbinop(yytext);
603 goto leave;
604 }
605
606 radix_digits_1:
607
608 c = input();
609 if (c >= '0' && c <= '0' + sc_min(10, radix) - 1)
610 goto radix_digits_1;
611 if (c >= 'a' && c <= 'a' + sc_min(36, radix) - 11)
612 goto radix_digits_1;
613 if (c >= 'A' && c <= 'A' + sc_min(36, radix) - 11)
614 goto radix_digits_1;
615 if (c == '.') {
616 goto radix_digits_2;
617 }
618 unput(c);
619 yytext[yylen] = 0;
620 r = processintradix(yytext, yylen, radix);
621 goto leave;
622
623 radix_digits_2:
624
625 c = input();
626 if (c >= '0' && c <= '0' + sc_min(10, radix) - 1)
627 goto radix_digits_2;
628 if (c >= 'A' && c <= 'A' + sc_min(36, radix) - 11)
629 goto radix_digits_2;
630 // do not allow lower case after decimal point.
631 unput(c);
632 yytext[yylen] = 0;
633 r = processfloatradix(yytext, yylen, radix);
634 goto leave;
635
636 hexdigits:
637
638 c = input();
639 if (c >= '0' && c <= '9')
640 goto hexdigits;
641 if (c >= 'a' && c <= 'f')
642 goto hexdigits;
643 if (c >= 'A' && c <= 'F')
644 goto hexdigits;
645 unput(c);
646 yytext[yylen] = 0;
647 r = processhex(yytext);
648 goto leave;
649
650 digits_1: /* number started with digits */
651
652 c = input();
653
654 if (c >= '0' && c <= '9')
655 goto digits_1;
656 else if (c == 'r') {
657 radix = sc_strtoi(yytext, yylen - 1, 10);
658 yylen = 0;
659 goto radix_digits_1;
660 } else if (c == 'e' || c == 'E')
661 goto expon_1;
662 else if (c == '.') {
663 c2 = input();
664 if (c2 >= '0' && c2 <= '9')
665 goto digits_2;
666 else {
667 unput(c2);
668 unput(c);
669 yytext[yylen] = 0;
670 r = processint(yytext);
671 goto leave;
672 }
673 } else if (c == 'b' || c == 's') {
674 d = input();
675 if (d >= '0' && d <= '9')
676 goto accidental1;
677 if (d == c)
678 goto accidental2;
679 goto accidental3;
680 accidental1:
681 d = input();
682 if (d >= '0' && d <= '9')
683 goto accidental1;
684 unput(d);
685 yytext[yylen] = 0;
686 r = processaccidental1(yytext);
687 goto leave;
688 accidental2:
689 d = input();
690 if (d == c)
691 goto accidental2;
692 accidental3:
693 unput(d);
694 yytext[yylen] = 0;
695 r = processaccidental2(yytext);
696 goto leave;
697 } else if (c == 'x') {
698 yylen = 0;
699 goto hexdigits;
700 } else {
701 unput(c);
702 yytext[yylen] = 0;
703 r = processint(yytext);
704 goto leave;
705 }
706
707 digits_2:
708
709 c = input();
710
711 if (c >= '0' && c <= '9')
712 goto digits_2;
713 else if (c == 'e' || c == 'E')
714 goto expon_1;
715 // else if (c == 'π' || c == '∏') {
716 // --yylen;
717 // yytext[yylen] = 0;
718 // r = processfloat(yytext, 1);
719 // goto leave;
720 // }
721 else {
722 unput(c);
723 yytext[yylen] = 0;
724 r = processfloat(yytext, 0);
725 goto leave;
726 }
727
728 expon_1: /* e has been seen, need digits */
729 c = input();
730
731 if (c >= '0' && c <= '9')
732 goto expon_3;
733 else if (c == '+' || c == '-')
734 goto expon_2;
735 else
736 goto error1;
737
738 expon_2: /* + or - seen but still need digits */
739 c = input();
740
741 if (c >= '0' && c <= '9')
742 goto expon_3;
743 else
744 goto error1;
745
746 expon_3:
747 c = input();
748
749 if (c >= '0' && c <= '9')
750 goto expon_3;
751 // else if (c == 'π' || c == '∏') {
752 // --yylen;
753 // yytext[yylen] = 0;
754 // r = processfloat(yytext, 1);
755 // goto leave;
756 // }
757 else {
758 unput(c);
759 yytext[yylen] = 0;
760 r = processfloat(yytext, 0);
761 goto leave;
762 }
763
764 symbol3 : {
765 int startline, endchar;
766 startline = lineno;
767 endchar = '\'';
768
769 /*do {
770 c = input();
771 } while (c != endchar && c != 0);*/
772 for (; yylen < MAXYYLEN;) {
773 c = input();
774 if (c == '\n' || c == '\r') {
775 post("Symbol open at end of line on line %d of %s\n", startline + errLineOffset,
776 printingCurrfilename.c_str());
777 yylen = 0;
778 r = 0;
779 goto leave;
780 }
781 if (c == '\\') {
782 yylen--;
783 c = input();
784 } else if (c == endchar)
785 break;
786 if (c == 0)
787 break;
788 }
789 if (c == 0) {
790 post("Open ended symbol started on line %d of %s\n", startline + errLineOffset, printingCurrfilename.c_str());
791 yylen = 0;
792 r = 0;
793 goto leave;
794 }
795 yytext[yylen] = 0;
796 yytext[yylen - 1] = 0;
797 r = processsymbol(yytext);
798 goto leave;
799 }
800
801 string1 : {
802 int startline, endchar;
803 startline = lineno;
804 endchar = '"';
805
806 for (; yylen < MAXYYLEN;) {
807 c = input();
808 if (c == '\\') {
809 yylen--;
810 c = input();
811 switch (c) {
812 case 'n':
813 yytext[yylen - 1] = '\n';
814 break;
815 case 'r':
816 yytext[yylen - 1] = '\r';
817 break;
818 case 't':
819 yytext[yylen - 1] = '\t';
820 break;
821 case 'f':
822 yytext[yylen - 1] = '\f';
823 break;
824 case 'v':
825 yytext[yylen - 1] = '\v';
826 break;
827 }
828 } else if (c == '\r')
829 c = '\n';
830 else if (c == endchar)
831 break;
832 if (c == 0)
833 break;
834 }
835 if (c == 0) {
836 post("Open ended string started on line %d of %s\n", startline + errLineOffset, printingCurrfilename.c_str());
837 yylen = 0;
838 r = 0;
839 goto leave;
840 }
841 yylen--;
842
843 do {
844 c = input0();
845 } while (c && isspace(c));
846
847 if (c == '"')
848 goto string1;
849 else if (c)
850 unput0(c);
851
852 yytext[yylen] = 0;
853 r = processstring(yytext);
854 goto leave;
855 }
856
857 comment1: /* comment -- to end of line */
858 do {
859 c = input0();
860 } while (c != '\n' && c != '\r' && c != 0);
861 yylen = 0;
862 if (c == 0) {
863 r = 0;
864 goto leave;
865 } else
866 goto start;
867
868 comment2 : {
869 int startline, clevel, prevc;
870 startline = lineno;
871 prevc = 0;
872 clevel = 1;
873 do {
874 c = input0();
875 if (c == '/' && prevc == '*') {
876 if (--clevel <= 0)
877 break;
878 else
879 prevc = c, c = input0(); // eat both characters
880 } else if (c == '*' && prevc == '/') {
881 clevel++;
882 prevc = c, c = input0(); // eat both characters
883 }
884 prevc = c;
885 } while (c != 0);
886 yylen = 0;
887 if (c == 0) {
888 post("Open ended comment started on line %d of %s\n", startline + errLineOffset, printingCurrfilename.c_str());
889 r = 0;
890 goto leave;
891 }
892 goto start;
893 }
894
895
896 error1:
897
898 yytext[yylen] = 0;
899
900 post("illegal input string '%s' \n in %s line %d char %d\n", yytext, printingCurrfilename.c_str(),
901 lineno + errLineOffset, charno);
902 post("code %d\n", c);
903 // postfl(" '%c' '%s'\n", c, binopchars);
904 // postfl("%d\n", strchr(binopchars, c));
905
906 error2:
907 post(" in %s line %d char %d\n", printingCurrfilename.c_str(), lineno + errLineOffset, charno);
908 r = BADTOKEN;
909 goto leave;
910
911 leave:
912 yytext[yylen] = 0;
913
914 #if DEBUGLEX
915 if (gDebugLexer)
916 postfl("yylex: %d '%s'\n", r, yytext);
917 #endif
918 // if (lexCmdLine>0) postfl("yylex: %d '%s'\n",r,yytext);
919 return r;
920 }
921
processbinop(char * token)922 int processbinop(char* token) {
923 PyrSymbol* sym;
924 PyrSlot slot;
925 PyrSlotNode* node;
926
927 #if DEBUGLEX
928 if (gDebugLexer)
929 postfl("processbinop: '%s'\n", token);
930 #endif
931 sym = getsym(token);
932 SetSymbol(&slot, sym);
933 node = newPyrSlotNode(&slot);
934 zzval = (intptr_t)node;
935 if (strcmp(token, "<-") == 0)
936 return LEFTARROW;
937 if (strcmp(token, "<>") == 0)
938 return READWRITEVAR;
939 if (strcmp(token, "|") == 0)
940 return '|';
941 if (strcmp(token, "<") == 0)
942 return '<';
943 if (strcmp(token, ">") == 0)
944 return '>';
945 if (strcmp(token, "-") == 0)
946 return '-';
947 if (strcmp(token, "*") == 0)
948 return '*';
949 if (strcmp(token, "+") == 0)
950 return '+';
951 return BINOP;
952 }
953
processkeywordbinop(char * token)954 int processkeywordbinop(char* token) {
955 PyrSymbol* sym;
956 PyrSlot slot;
957 PyrSlotNode* node;
958
959 // post("'%s' file '%s'\n", token, currfilename);
960
961 #if DEBUGLEX
962 if (gDebugLexer)
963 postfl("processkeywordbinop: '%s'\n", token);
964 #endif
965 token[strlen(token) - 1] = 0; // strip off colon
966 sym = getsym(token);
967 SetSymbol(&slot, sym);
968 node = newPyrSlotNode(&slot);
969 zzval = (intptr_t)node;
970 return KEYBINOP;
971 }
972
processident(char * token)973 int processident(char* token) {
974 char c;
975 PyrSymbol* sym;
976
977 PyrSlot slot;
978 PyrParseNode* node;
979
980 c = token[0];
981 zzval = (intptr_t)-1;
982
983 #if DEBUGLEX
984 if (gDebugLexer)
985 postfl("word: '%s'\n", token);
986 #endif
987 /*
988 strcpy(uptoken, token);
989 for (str = uptoken; *str; ++str) {
990 if (*str >= 'a' && *str <= 'z') *str += 'A' - 'a';
991 }*/
992
993 if (token[0] == '_') {
994 if (token[1] == 0) {
995 node = newPyrCurryArgNode();
996 zzval = (intptr_t)node;
997 return CURRYARG;
998 } else {
999 sym = getsym(token);
1000 SetSymbol(&slot, sym);
1001 node = newPyrSlotNode(&slot);
1002 zzval = (intptr_t)node;
1003 return PRIMITIVENAME;
1004 }
1005 }
1006 if (token[0] >= 'A' && token[0] <= 'Z') {
1007 sym = getsym(token);
1008 SetSymbol(&slot, sym);
1009 node = newPyrSlotNode(&slot);
1010 zzval = (intptr_t)node;
1011 #if DEBUGLEX
1012 if (gDebugLexer)
1013 postfl("CLASSNAME: '%s'\n", token);
1014 #endif
1015 return CLASSNAME;
1016 }
1017 if (strcmp("var", token) == 0)
1018 return VAR;
1019 if (strcmp("arg", token) == 0)
1020 return ARG;
1021 if (strcmp("classvar", token) == 0)
1022 return CLASSVAR;
1023 if (strcmp("const", token) == 0)
1024 return SC_CONST;
1025
1026 if (strcmp("while", token) == 0) {
1027 sym = getsym(token);
1028 SetSymbol(&slot, sym);
1029 node = newPyrSlotNode(&slot);
1030 zzval = (intptr_t)node;
1031 return WHILE;
1032 }
1033 if (strcmp("pi", token) == 0) {
1034 SetFloat(&slot, pi);
1035 node = newPyrSlotNode(&slot);
1036 zzval = (intptr_t)node;
1037 return PIE;
1038 }
1039 if (strcmp("true", token) == 0) {
1040 SetTrue(&slot);
1041 node = newPyrSlotNode(&slot);
1042 zzval = (intptr_t)node;
1043 return TRUEOBJ;
1044 }
1045 if (strcmp("false", token) == 0) {
1046 SetFalse(&slot);
1047 node = newPyrSlotNode(&slot);
1048 zzval = (intptr_t)node;
1049 return FALSEOBJ;
1050 }
1051 if (strcmp("nil", token) == 0) {
1052 SetNil(&slot);
1053 node = newPyrSlotNode(&slot);
1054 zzval = (intptr_t)node;
1055 return NILOBJ;
1056 }
1057 if (strcmp("inf", token) == 0) {
1058 SetFloat(&slot, std::numeric_limits<double>::infinity());
1059 node = newPyrSlotNode(&slot);
1060 zzval = (intptr_t)node;
1061 return SC_FLOAT;
1062 }
1063
1064 sym = getsym(token);
1065
1066 SetSymbol(&slot, sym);
1067 node = newPyrSlotNode(&slot);
1068 zzval = (intptr_t)node;
1069 return NAME;
1070 }
1071
processhex(char * s)1072 int processhex(char* s) {
1073 PyrSlot slot;
1074 PyrSlotNode* node;
1075 char* c;
1076 int val;
1077 #if DEBUGLEX
1078 if (gDebugLexer)
1079 postfl("processhex: '%s'\n", s);
1080 #endif
1081
1082 c = s;
1083 val = 0;
1084 while (*c) {
1085 if (*c >= '0' && *c <= '9')
1086 val = val * 16 + *c - '0';
1087 else if (*c >= 'a' && *c <= 'z')
1088 val = val * 16 + *c - 'a' + 10;
1089 else if (*c >= 'A' && *c <= 'Z')
1090 val = val * 16 + *c - 'A' + 10;
1091 c++;
1092 }
1093
1094 SetInt(&slot, val);
1095 node = newPyrSlotNode(&slot);
1096 zzval = (intptr_t)node;
1097 return INTEGER;
1098 }
1099
1100
processintradix(char * s,int n,int radix)1101 int processintradix(char* s, int n, int radix) {
1102 PyrSlot slot;
1103 PyrSlotNode* node;
1104 #if DEBUGLEX
1105 if (gDebugLexer)
1106 postfl("processintradix: '%s'\n", s);
1107 #endif
1108
1109 SetInt(&slot, sc_strtoi(s, n, radix));
1110 node = newPyrSlotNode(&slot);
1111 zzval = (intptr_t)node;
1112 return INTEGER;
1113 }
1114
processfloatradix(char * s,int n,int radix)1115 int processfloatradix(char* s, int n, int radix) {
1116 PyrSlot slot;
1117 PyrSlotNode* node;
1118 #if DEBUGLEX
1119 if (gDebugLexer)
1120 postfl("processfloatradix: '%s'\n", s);
1121 #endif
1122
1123 SetFloat(&slot, sc_strtof(s, n, radix));
1124 node = newPyrSlotNode(&slot);
1125 zzval = (intptr_t)node;
1126 return SC_FLOAT;
1127 }
1128
processint(char * s)1129 int processint(char* s) {
1130 PyrSlot slot;
1131 PyrSlotNode* node;
1132 #if DEBUGLEX
1133 if (gDebugLexer)
1134 postfl("processint: '%s'\n", s);
1135 #endif
1136
1137 SetInt(&slot, atoi(s));
1138 node = newPyrSlotNode(&slot);
1139 zzval = (intptr_t)node;
1140 return INTEGER;
1141 }
1142
processchar(int c)1143 int processchar(int c) {
1144 PyrSlot slot;
1145 PyrSlotNode* node;
1146 #if DEBUGLEX
1147 if (gDebugLexer)
1148 postfl("processhex: '%c'\n", c);
1149 #endif
1150
1151 SetChar(&slot, c);
1152 node = newPyrSlotNode(&slot);
1153 zzval = (intptr_t)node;
1154 return ASCII;
1155 }
1156
processfloat(char * s,int sawpi)1157 int processfloat(char* s, int sawpi) {
1158 PyrSlot slot;
1159 PyrSlotNode* node;
1160 double z;
1161 #if DEBUGLEX
1162 if (gDebugLexer)
1163 postfl("processfloat: '%s'\n", s);
1164 #endif
1165
1166 if (sawpi) {
1167 z = atof(s) * pi;
1168 SetFloat(&slot, z);
1169 } else {
1170 SetFloat(&slot, atof(s));
1171 }
1172 node = newPyrSlotNode(&slot);
1173 zzval = (intptr_t)node;
1174 return SC_FLOAT;
1175 }
1176
1177
processaccidental1(char * s)1178 int processaccidental1(char* s) {
1179 PyrSlot slot;
1180 PyrSlotNode* node;
1181 char* c;
1182 double degree = 0.;
1183 double cents = 0.;
1184 double centsdiv = 1000.;
1185 #if 0
1186 printf("processaccidental1: '%s'\n",s);
1187 #endif
1188
1189 c = s;
1190 while (*c) {
1191 if (*c >= '0' && *c <= '9')
1192 degree = degree * 10. + *c - '0';
1193 else
1194 break;
1195 c++;
1196 }
1197
1198 if (*c == 'b')
1199 centsdiv = -1000.;
1200 else if (*c == 's')
1201 centsdiv = 1000.;
1202 c++;
1203
1204 while (*c) {
1205 if (*c >= '0' && *c <= '9') {
1206 cents = cents * 10. + *c - '0';
1207 } else
1208 break;
1209 c++;
1210 }
1211
1212 if (cents > 499.)
1213 cents = 499.;
1214
1215 SetFloat(&slot, degree + cents / centsdiv);
1216 node = newPyrSlotNode(&slot);
1217 zzval = (intptr_t)node;
1218 return ACCIDENTAL;
1219 }
1220
processaccidental2(char * s)1221 int processaccidental2(char* s) {
1222 PyrSlot slot;
1223 PyrSlotNode* node;
1224 char* c;
1225 double degree = 0.;
1226 double semitones = 0.;
1227 #if 0
1228 printf("processaccidental2: '%s'\n",s);
1229 #endif
1230
1231 c = s;
1232 while (*c) {
1233 if (*c >= '0' && *c <= '9')
1234 degree = degree * 10. + *c - '0';
1235 else
1236 break;
1237 c++;
1238 }
1239
1240 while (*c) {
1241 if (*c == 'b')
1242 semitones -= 1.;
1243 else if (*c == 's')
1244 semitones += 1.;
1245 c++;
1246 }
1247
1248 if (semitones > 4.)
1249 semitones = 4.;
1250 else if (semitones < -4.)
1251 semitones = -4.;
1252
1253 SetFloat(&slot, degree + semitones / 10.);
1254 node = newPyrSlotNode(&slot);
1255 zzval = (intptr_t)node;
1256 return ACCIDENTAL;
1257 }
1258
processsymbol(char * s)1259 int processsymbol(char* s) {
1260 PyrSlot slot;
1261 PyrSlotNode* node;
1262 PyrSymbol* sym;
1263 #if DEBUGLEX
1264 if (gDebugLexer)
1265 postfl("processsymbol: '%s'\n", s);
1266 #endif
1267 sym = getsym(s + 1);
1268
1269 SetSymbol(&slot, sym);
1270 node = newPyrSlotNode(&slot);
1271 zzval = (intptr_t)node;
1272 return SYMBOL;
1273 }
1274
processstring(char * s)1275 int processstring(char* s) {
1276 PyrSlot slot;
1277 PyrSlotNode* node;
1278 PyrString* string;
1279 #if DEBUGLEX
1280 if (gDebugLexer)
1281 postfl("processstring: '%s'\n", s);
1282 #endif
1283 int flags = compilingCmdLine ? obj_immutable : obj_permanent | obj_immutable;
1284 string = newPyrString(gMainVMGlobals->gc, s + 1, flags, false);
1285 SetObject(&slot, string);
1286 node = newPyrSlotNode(&slot);
1287 zzval = (intptr_t)node;
1288 return STRING;
1289 }
1290
yyerror(const char * s)1291 void yyerror(const char* s) {
1292 parseFailed = 1;
1293 yytext[yylen] = 0;
1294 error("%s\n", s);
1295 postErrorLine(lineno, linepos, charno);
1296 // Debugger();
1297 }
1298
fatal()1299 void fatal() {
1300 parseFailed = 1;
1301 yytext[yylen] = 0;
1302 error("Parse error\n");
1303 postErrorLine(lineno, linepos, charno);
1304 // Debugger();
1305 }
1306
postErrorLine(int linenum,int start,int charpos)1307 void postErrorLine(int linenum, int start, int charpos) {
1308 int i, j, end, pos;
1309 char str[256];
1310
1311 // post("start %d\n", start);
1312 // parseFailed = true;
1313 post(" in %s\n", printingCurrfilename.c_str());
1314 post(" line %d char %d:\n\n", linenum + errLineOffset, charpos);
1315 // nice: postfl previous line for context
1316
1317 // postfl("text '%s' %d\n", text, text);
1318
1319 // postfl error line for context
1320 pos = start + charpos;
1321 for (i = pos; i < textlen; ++i) {
1322 if (text[i] == 0 || text[i] == '\r' || text[i] == '\n')
1323 break;
1324 }
1325 end = i;
1326 for (i = start, j = 0; i < end && j < 255; ++i) {
1327 str[j++] = text[i];
1328 }
1329 str[j] = 0;
1330 post(" %s\n ", str);
1331 for (i = 0; i < charpos - yylen; i++)
1332 post(" ");
1333 for (i = 0; i < yylen; i++)
1334 post("^");
1335 post("\n");
1336
1337 i = end + 1;
1338 if (i < textlen) {
1339 // postfl following line for context
1340 for (j = 0; j < 255 && i < textlen; ++i) {
1341 if (text[i] == 0 || text[i] == '\r' || text[i] == '\n')
1342 break;
1343 str[j++] = text[i];
1344 }
1345 str[j] = 0;
1346 post(" %s\n", str);
1347 }
1348 post("-----------------------------------\n", str);
1349 }
1350
1351 void pstrncpy(unsigned char* s1, unsigned char* s2, int n);
pstrncpy(unsigned char * s1,unsigned char * s2,int n)1352 void pstrncpy(unsigned char* s1, unsigned char* s2, int n) {
1353 int i, m;
1354 m = *s2++;
1355 n = (n < m) ? n : m;
1356 *s1 = n;
1357 s1++;
1358 for (i = 0; i < n; ++i) {
1359 *s1 = *s2;
1360 s1++;
1361 s2++;
1362 }
1363 }
1364
1365 int pstrcmp(unsigned char* s1, unsigned char* s2);
pstrcmp(unsigned char * s1,unsigned char * s2)1366 int pstrcmp(unsigned char* s1, unsigned char* s2) {
1367 int i, len1, len2, len;
1368 len1 = *s1++;
1369 len2 = *s2++;
1370 len = sc_min(len1, len2);
1371 for (i = 0; i < len; ++i) {
1372 if (s1[i] < s2[i])
1373 return -1;
1374 if (s1[i] > s2[i])
1375 return 1;
1376 }
1377 if (len1 < len2)
1378 return -1;
1379 if (len1 > len2)
1380 return 1;
1381 return 0;
1382 }
1383
scanForClosingBracket()1384 bool scanForClosingBracket() {
1385 int r, c, startLevel;
1386 intptr_t d;
1387 bool res = true;
1388 // finite state machine to parse input stream into tokens
1389
1390 #if DEBUGLEX
1391 if (gDebugLexer)
1392 postfl("->scanForClosingBracket\n");
1393 #endif
1394 startLevel = brackets.num;
1395 start:
1396 c = input0();
1397
1398 if (c == 0)
1399 goto leave;
1400 else if (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\v' || c == '\f') {
1401 goto start;
1402 } else if (c == '\'')
1403 goto symbol3;
1404 else if (c == '"')
1405 goto string1;
1406 else if (c == '/') {
1407 c = input0();
1408 if (c == '/')
1409 goto comment1;
1410 else if (c == '*')
1411 goto comment2;
1412 else {
1413 unput(c);
1414 goto start;
1415 }
1416 } else if (c == '$') {
1417 c = input0();
1418 if (c == '\\') {
1419 c = input0();
1420 switch (c) {
1421 case 'n':
1422 c = '\n';
1423 break;
1424 case 'r':
1425 c = '\r';
1426 break;
1427 case 't':
1428 c = '\t';
1429 break;
1430 case 'f':
1431 c = '\f';
1432 break;
1433 case 'v':
1434 c = '\v';
1435 break;
1436 }
1437 }
1438 goto start;
1439 } else if (c == OPENPAREN || c == OPENSQUAR || c == OPENCURLY) {
1440 pushls(&brackets, (intptr_t)c);
1441 r = c;
1442 goto start;
1443 } else if (c == CLOSSQUAR) {
1444 if (!emptyls(&brackets)) {
1445 if ((d = popls(&brackets)) != OPENSQUAR) {
1446 fatal();
1447 post("opening bracket was a '%c', but found a '%c'\n", d, c);
1448 goto error1;
1449 }
1450 } else {
1451 fatal();
1452 post("unmatched '%c'\n", c);
1453 goto error1;
1454 }
1455 r = c;
1456 if (brackets.num < startLevel)
1457 goto leave;
1458 else
1459 goto start;
1460 } else if (c == CLOSPAREN) {
1461 if (!emptyls(&brackets)) {
1462 if ((d = popls(&brackets)) != (intptr_t)OPENPAREN) {
1463 fatal();
1464 post("opening bracket was a '%c', but found a '%c'\n", d, c);
1465 goto error1;
1466 }
1467 } else {
1468 fatal();
1469 post("unmatched '%c'\n", c);
1470 goto error1;
1471 }
1472 if (brackets.num < startLevel)
1473 goto leave;
1474 else
1475 goto start;
1476 } else if (c == CLOSCURLY) {
1477 if (!emptyls(&brackets)) {
1478 if ((d = popls(&brackets)) != OPENCURLY) {
1479 fatal();
1480 post("opening bracket was a '%c', but found a '%c'\n", d, c);
1481 goto error1;
1482 }
1483 } else {
1484 fatal();
1485 post("unmatched '%c'\n", c);
1486 goto error1;
1487 }
1488 if (brackets.num < startLevel)
1489 goto leave;
1490 else
1491 goto start;
1492 } else {
1493 goto start;
1494 }
1495 symbol3 : {
1496 int startline, endchar;
1497 startline = lineno;
1498 endchar = '\'';
1499
1500 do {
1501 c = input0();
1502 if (c == '\\') {
1503 input0();
1504 }
1505 } while (c != endchar && c != 0);
1506 if (c == 0) {
1507 post("Open ended symbol started on line %d of %s\n", startline, printingCurrfilename.c_str());
1508 goto error2;
1509 }
1510 goto start;
1511 }
1512
1513 string1 : {
1514 int startline, endchar;
1515 startline = lineno;
1516 endchar = '\"';
1517
1518 do {
1519 c = input0();
1520 if (c == '\\') {
1521 input0();
1522 }
1523 } while (c != endchar && c != 0);
1524 if (c == 0) {
1525 post("Open ended string started on line %d of %s\n", startline, printingCurrfilename.c_str());
1526 goto error2;
1527 }
1528 goto start;
1529 }
1530 comment1: /* comment -- to end of line */
1531 do {
1532 c = input0();
1533 } while (c != '\n' && c != '\r' && c != 0);
1534 if (c == 0) {
1535 goto leave;
1536 } else
1537 goto start;
1538
1539 comment2 : {
1540 int startline, clevel, prevc;
1541 startline = lineno;
1542 prevc = 0;
1543 clevel = 1;
1544 do {
1545 c = input0();
1546 if (c == '/' && prevc == '*') {
1547 if (--clevel <= 0)
1548 break;
1549 else
1550 prevc = c, c = input0(); // eat both characters
1551 } else if (c == '*' && prevc == '/') {
1552 clevel++;
1553 prevc = c, c = input0(); // eat both characters
1554 }
1555 prevc = c;
1556 } while (c != 0);
1557 if (c == 0) {
1558 post("Open ended comment started on line %d of %s\n", startline, printingCurrfilename.c_str());
1559 goto error2;
1560 }
1561 goto start;
1562 }
1563
1564 error1:
1565 post(" in %s line %d char %d\n", printingCurrfilename.c_str(), lineno, charno);
1566 res = false;
1567 goto leave;
1568
1569 error2:
1570 res = false;
1571 goto leave;
1572
1573 leave:
1574 #if DEBUGLEX
1575 if (gDebugLexer)
1576 postfl("<-scanForClosingBracket\n");
1577 #endif
1578 return res;
1579 }
1580
1581
1582 int numClassDeps;
1583 static ClassExtFile* sClassExtFiles;
1584 static ClassExtFile* eClassExtFiles;
1585
1586 ClassExtFile* newClassExtFile(PyrSymbol* fileSym, int startPos, int endPos);
newClassExtFile(PyrSymbol * fileSym,int startPos,int endPos)1587 ClassExtFile* newClassExtFile(PyrSymbol* fileSym, int startPos, int endPos) {
1588 ClassExtFile* classext;
1589 classext = (ClassExtFile*)pyr_pool_compile->Alloc(sizeof(ClassExtFile));
1590 classext->fileSym = fileSym;
1591 classext->next = nullptr;
1592 classext->startPos = startPos;
1593 classext->endPos = endPos;
1594 if (!sClassExtFiles)
1595 sClassExtFiles = classext;
1596 else
1597 eClassExtFiles->next = classext;
1598 eClassExtFiles = classext;
1599 return classext;
1600 }
1601
1602
newClassDependancy(PyrSymbol * className,PyrSymbol * superClassName,PyrSymbol * fileSym,int startPos,int endPos,int lineOffset)1603 ClassDependancy* newClassDependancy(PyrSymbol* className, PyrSymbol* superClassName, PyrSymbol* fileSym, int startPos,
1604 int endPos, int lineOffset) {
1605 ClassDependancy* classdep;
1606
1607 // post("classdep '%s' '%s' '%s' %d %d\n", className->name, superClassName->name,
1608 // fileSym->name, className, superClassName);
1609 // pyrmalloc:
1610 // lifetime: kill after compile.
1611 numClassDeps++;
1612 if (className->classdep) {
1613 error("duplicate Class found: '%s' \n", className->name);
1614 post("%s\n", className->classdep->fileSym->name);
1615 postfl("%s\n\n", fileSym->name);
1616 return className->classdep;
1617 }
1618 classdep = (ClassDependancy*)pyr_pool_compile->Alloc(sizeof(ClassDependancy));
1619 MEMFAIL(text);
1620 classdep->className = className;
1621 classdep->superClassName = superClassName;
1622 classdep->fileSym = fileSym;
1623 classdep->superClassDep = nullptr;
1624 classdep->next = nullptr;
1625 classdep->subclasses = nullptr;
1626
1627 classdep->startPos = startPos;
1628 classdep->endPos = endPos;
1629 classdep->lineOffset = lineOffset;
1630
1631 className->classdep = classdep;
1632 return classdep;
1633 }
1634
buildDepTree()1635 void buildDepTree() {
1636 ClassDependancy* next;
1637 SymbolTable* symbolTable = gMainVMGlobals->symbolTable;
1638
1639 // postfl("->buildDepTree\n"); fflush(stdout);
1640 for (int i = 0; i < symbolTable->TableSize(); ++i) {
1641 PyrSymbol* sym = symbolTable->Get(i);
1642 if (sym && (sym->flags & sym_Class)) {
1643 if (sym->classdep) {
1644 if (sym->classdep->superClassName->classdep) {
1645 next = sym->classdep->superClassName->classdep->subclasses;
1646 sym->classdep->superClassName->classdep->subclasses = sym->classdep;
1647 sym->classdep->next = next;
1648 } else if (sym->classdep->superClassName != s_none) {
1649 error("Superclass '%s' of class '%s' is not defined in any file.\n%s\n",
1650 sym->classdep->superClassName->name, sym->classdep->className->name,
1651 sym->classdep->fileSym->name);
1652 }
1653 }
1654 }
1655 }
1656 // postfl("<-buildDepTree\n"); fflush(stdout);
1657 }
1658
1659 extern PyrClass* gClassList;
1660
1661 ClassDependancy** gClassCompileOrder;
1662 int gClassCompileOrderNum = 0;
1663 int gClassCompileOrderSize = 1000;
1664
1665 void compileDepTree();
1666
traverseFullDepTree()1667 void traverseFullDepTree() {
1668 // postfl("->traverseFullDepTree\n"); fflush(stdout);
1669 gClassCompileOrderNum = 0;
1670 gClassCompileOrder = (ClassDependancy**)pyr_pool_compile->Alloc(gClassCompileOrderSize * sizeof(ClassDependancy));
1671 MEMFAIL(gClassCompileOrder);
1672
1673 // parse and compile all files
1674 initParser(); // sets compiler errors to 0
1675 gParserResult = -1;
1676
1677 traverseDepTree(s_object->classdep, 0);
1678 compileDepTree(); // compiles backwards using the order defined in gClassCompileOrder
1679 compileClassExtensions();
1680
1681 pyr_pool_compile->Free(gClassCompileOrder);
1682
1683 finiParser();
1684 // postfl("<-traverseFullDepTree\n"); fflush(stdout);
1685 }
1686
1687
traverseDepTree(ClassDependancy * classdep,int level)1688 void traverseDepTree(ClassDependancy* classdep, int level) {
1689 ClassDependancy* subclassdep;
1690
1691 if (!classdep)
1692 return;
1693
1694 subclassdep = classdep->subclasses;
1695 for (; subclassdep; subclassdep = subclassdep->next) {
1696 traverseDepTree(subclassdep, level + 1);
1697 }
1698 if (gClassCompileOrderNum > gClassCompileOrderSize) {
1699 gClassCompileOrderSize *= 2;
1700 gClassCompileOrder = (ClassDependancy**)pyr_pool_compile->Realloc(
1701 gClassCompileOrder, gClassCompileOrderSize * sizeof(ClassDependancy));
1702 MEMFAIL(gClassCompileOrder);
1703 }
1704
1705 /* postfl("traverse level:%d, gClassCompileOrderNum:%d, '%s' '%s' '%s'\n", level, gClassCompileOrderNum,
1706 classdep->className->name, classdep->superClassName->name, classdep->fileSym->name); fflush(stdout);
1707 */
1708
1709 gClassCompileOrder[gClassCompileOrderNum++] = classdep;
1710 }
1711
1712
compileClass(PyrSymbol * fileSym,int startPos,int endPos,int lineOffset)1713 void compileClass(PyrSymbol* fileSym, int startPos, int endPos, int lineOffset) {
1714 // fprintf(stderr, "compileClass: %d\n", fileSym->u.index);
1715
1716 gCompilingFileSym = fileSym;
1717 gCompilingVMGlobals = nullptr;
1718 gRootParseNode = nullptr;
1719 initParserPool();
1720 if (startLexer(fileSym, bfs::path(), startPos, endPos, lineOffset)) {
1721 // postfl("->Parsing %s\n", fileSym->name); fflush(stdout);
1722 parseFailed = yyparse();
1723 // postfl("<-Parsing %s %d\n", fileSym->name, parseFailed); fflush(stdout);
1724 // post("parseFailed %d\n", parseFailed); fflush(stdout);
1725 if (!parseFailed && gRootParseNode) {
1726 // postfl("Compiling nodes %p\n", gRootParseNode);fflush(stdout);
1727 compilingCmdLine = false;
1728 compileNodeList(gRootParseNode, true);
1729 // postfl("done compiling\n");fflush(stdout);
1730 } else {
1731 compileErrors++;
1732 bfs::path pathname(fileSym->name);
1733 error("file '%s' parse failed\n", SC_Codecvt::path_to_utf8_str(pathname).c_str());
1734 postfl("error parsing\n");
1735 }
1736 finiLexer();
1737 } else {
1738 error("file '%s' open failed\n", fileSym->name);
1739 }
1740 freeParserPool();
1741 }
1742
compileDepTree()1743 void compileDepTree() {
1744 ClassDependancy* classdep;
1745 int i;
1746
1747 for (i = gClassCompileOrderNum - 1; i >= 0; --i) {
1748 classdep = gClassCompileOrder[i];
1749 /*postfl("compile %d '%s' '%s' '%s'...%d/%d/%d\n", i, classdep->className->name, classdep->superClassName->name,
1750 classdep->fileSym->name, classdep->startLine, classdep->endLine, classDep->lineOffset);*/
1751 compileClass(classdep->fileSym, classdep->startPos, classdep->endPos, classdep->lineOffset);
1752 }
1753 // postfl("<compile\n");
1754 }
1755
compileClassExtensions()1756 void compileClassExtensions() {
1757 if (sClassExtFiles) {
1758 ClassExtFile* classext = sClassExtFiles;
1759 do {
1760 // postfl("compile class ext: %d/%d\n", classext->startPos, classext->endPos);
1761 compileClass(classext->fileSym, classext->startPos, classext->endPos, -1);
1762 classext = classext->next;
1763 } while (classext);
1764 }
1765 }
1766
1767 void findDiscrepancy();
1768
traverseFullDepTree2()1769 void traverseFullDepTree2() {
1770 // assign a class index to all classes
1771 if (!parseFailed && !compileErrors) {
1772 buildClassTree();
1773 gNumClasses = 0;
1774
1775 // now I index them during pass one
1776 indexClassTree(class_object, 0);
1777 setSelectorFlags();
1778 if (2 * numClassDeps != gNumClasses) {
1779 error("There is a discrepancy.\n");
1780 /* not always correct
1781 if(2*numClassDeps < gNumClasses) {
1782 post("Duplicate files may exist in the directory structure.\n");
1783 } else {
1784 post("Some class files may be missing.\n");
1785 }
1786 */
1787 post("numClassDeps %d gNumClasses %d\n", numClassDeps, gNumClasses);
1788 findDiscrepancy();
1789 compileErrors++;
1790 } else {
1791 double elapsed;
1792 buildBigMethodMatrix();
1793 SymbolTable* symbolTable = gMainVMGlobals->symbolTable;
1794 post("\tNumber of Symbols %d\n", symbolTable->NumItems());
1795 post("\tByte Code Size %d\n", totalByteCodes);
1796 // elapsed = TickCount() - compileStartTime;
1797 // elapsed = 0;
1798 elapsed = elapsedTime() - compileStartTime;
1799 post("\tcompiled %d files in %.2f seconds\n", gNumCompiledFiles, elapsed);
1800 if (numOverwrites == 1) {
1801 post("\nInfo: One method is currently overwritten by an extension. To see which, "
1802 "execute:\nMethodOverride.printAll\n\n");
1803 } else if (numOverwrites > 1) {
1804 post("\nInfo: %i methods are currently overwritten by extensions. To see which, "
1805 "execute:\nMethodOverride.printAll\n\n",
1806 numOverwrites);
1807 }
1808 post("compile done\n");
1809 }
1810 }
1811 }
1812
parseOneClass(PyrSymbol * fileSym)1813 bool parseOneClass(PyrSymbol* fileSym) {
1814 int token;
1815 PyrSymbol *className, *superClassName;
1816 ClassDependancy* classdep;
1817 bool res;
1818
1819 int startPos, startLineOffset;
1820
1821 res = true;
1822
1823 startPos = textpos;
1824 startLineOffset = lineno - 1;
1825
1826 token = yylex();
1827 if (token == CLASSNAME) {
1828 className = slotRawSymbol(&((PyrSlotNode*)zzval)->mSlot);
1829 // I think this is wrong: zzval is space pool alloced
1830 // pyrfree((PyrSlot*)zzval);
1831
1832 token = yylex();
1833 if (token == 0)
1834 return false;
1835 if (token == OPENSQUAR) {
1836 scanForClosingBracket(); // eat indexing spec
1837 token = yylex();
1838 if (token == 0)
1839 return false;
1840 }
1841 if (token == ':') {
1842 token = yylex(); // get super class
1843 if (token == 0)
1844 return false;
1845 if (token == CLASSNAME) {
1846 superClassName = slotRawSymbol(&((PyrSlotNode*)zzval)->mSlot);
1847 // I think this is wrong: zzval is space pool alloced
1848 // pyrfree((PyrSlot*)zzval);
1849 token = yylex();
1850 if (token == 0)
1851 return false;
1852 if (token == OPENCURLY) {
1853 scanForClosingBracket(); // eat class body
1854 classdep =
1855 newClassDependancy(className, superClassName, fileSym, startPos, textpos, startLineOffset);
1856 } else {
1857 compileErrors++;
1858 postfl("Expected %c. got token: '%s' %d\n", OPENCURLY, yytext, token);
1859 postErrorLine(lineno, linepos, charno);
1860 return false;
1861 }
1862 } else {
1863 compileErrors++;
1864 post("Expected superclass name. got token: '%s' %d\n", yytext, token);
1865 postErrorLine(lineno, linepos, charno);
1866 return false;
1867 }
1868 } else if (token == OPENCURLY) {
1869 if (className == s_object)
1870 superClassName = s_none;
1871 else
1872 superClassName = s_object;
1873 scanForClosingBracket(); // eat class body
1874 classdep = newClassDependancy(className, superClassName, fileSym, startPos, textpos, startLineOffset);
1875 } else {
1876 compileErrors++;
1877 post("Expected ':' or %c. got token: '%s' %d\n", OPENCURLY, yytext, token);
1878 postErrorLine(lineno, linepos, charno);
1879 return false;
1880 }
1881 } else if (token == '+') {
1882 token = yylex();
1883 if (token == 0)
1884 return false;
1885 scanForClosingBracket();
1886
1887 newClassExtFile(fileSym, startPos, textpos);
1888 return false;
1889 } else {
1890 if (token != 0) {
1891 compileErrors++;
1892 post("Expected class name. got token: '%s' %d\n", yytext, token);
1893 postErrorLine(lineno, linepos, charno);
1894 return false;
1895 } else {
1896 res = false;
1897 }
1898 }
1899 return res;
1900 }
1901
initPassOne()1902 void initPassOne() {
1903 // dump_pool_histo(pyr_pool_runtime);
1904 pyr_pool_runtime->FreeAllInternal();
1905 // dump_pool_histo(pyr_pool_runtime);
1906 // gPermanentObjPool.Init(pyr_pool_runtime, PERMOBJCHUNK);
1907 sClassExtFiles = nullptr;
1908
1909 void* ptr = pyr_pool_runtime->Alloc(sizeof(SymbolTable));
1910 gMainVMGlobals->symbolTable = new (ptr) SymbolTable(pyr_pool_runtime, 65536);
1911
1912 initSymbols(); // initialize symbol globals
1913 initSpecialSelectors();
1914 initSpecialClasses();
1915 initClasses();
1916 initParserPool();
1917 initParseNodes();
1918 initPrimitives();
1919
1920 initLexer();
1921
1922 compileErrors = 0;
1923 numClassDeps = 0;
1924 compiledOK = false;
1925 compiledDirectories.clear();
1926
1927 // main class library folder: only used for relative path resolution
1928 gCompileDir = SC_Filesystem::instance().getDirectory(DirName::Resource) / "SCClassLibrary";
1929 }
1930
finiPassOne()1931 void finiPassOne() {
1932 // postfl("->finiPassOne\n");
1933 freeParserPool();
1934 // postfl("<-finiPassOne\n");
1935 }
1936
1937 /**
1938 * \brief \c true if \c dir is one of the language config's default classlib directories
1939 */
isDefaultClassLibraryDirectory(const bfs::path & dir)1940 static bool isDefaultClassLibraryDirectory(const bfs::path& dir) {
1941 auto const& defaultDirs = gLanguageConfig->defaultClassLibraryDirectories();
1942 auto const iter = std::find(defaultDirs.begin(), defaultDirs.end(), dir);
1943 return iter != defaultDirs.end();
1944 }
1945
1946 /**
1947 * \brief Handles a missing directory encountered during compilation.
1948 *
1949 * If the directory is one of the default directories traversed during compilation,
1950 * try to create it, silently ignoring failure (most likely from permissions failure).
1951 * Otherwise, warn the user to help catch mistyped/missing directory names. See #3468.
1952 */
passOne_HandleMissingDirectory(const bfs::path & dir)1953 static void passOne_HandleMissingDirectory(const bfs::path& dir) {
1954 if (isDefaultClassLibraryDirectory(dir)) {
1955 boost::system::error_code ec {};
1956 bfs::create_directories(dir, ec);
1957 } else {
1958 post("WARNING: Could not open directory: '%s'\n"
1959 "\tTo resolve this, either create the directory or remove it from your compilation paths.\n\n",
1960 SC_Codecvt::path_to_utf8_str(dir).c_str());
1961 }
1962 }
1963
relativeToCompileDir(const bfs::path & p)1964 bfs::path relativeToCompileDir(const bfs::path& p) { return bfs::relative(p, gCompileDir); }
1965
1966 /** \brief Determines whether the directory should be skipped during compilation.
1967 *
1968 * \param dir : The directory to check, as a `path` object
1969 * \returns `true` iff any of the following conditions is true:
1970 * - the directory has already been compiled
1971 * - the language configuration says this path is excluded
1972 * - SC_Filesystem::shouldNotCompileDirectory(dir) returns `true`
1973 */
passOne_ShouldSkipDirectory(const bfs::path & dir)1974 static bool passOne_ShouldSkipDirectory(const bfs::path& dir) {
1975 return (compiledDirectories.find(dir) != compiledDirectories.end())
1976 || (gLanguageConfig && gLanguageConfig->pathIsExcluded(dir))
1977 || (SC_Filesystem::instance().shouldNotCompileDirectory(dir));
1978 }
1979
1980 /** \brief Compile the contents of a single directory
1981 *
1982 * This method compiles any .sc files in a single directory, working
1983 * via depth-first recursion. This routine is designed to fail gracefully,
1984 * and only indicates failure if something truly unexpected happens. These
1985 * conditions are:
1986 * - an error occurred while trying to open a directory, other than the case
1987 * the case that the object doesn't exist.
1988 * - an error occurred while calling `passOne_processOneFile` on a file
1989 * - an error occurred in a recursive call of this routine on a macOS alias
1990 * Otherwise, this method returns success, even if:
1991 * - `dir` does not exist
1992 * - Iterating to the next file fails for any reason at all
1993 *
1994 * This method returns with a success state immediately if the directory
1995 * should not be compiled according to the language configuration.
1996 *
1997 * \param dir : The directory to traverse, as a `path` object
1998 * \returns `true` if processing was successful, `false` if it failed.
1999 * See above for what constitutes success and failure conditions.
2000 */
passOne_ProcessDir(const bfs::path & dir)2001 static bool passOne_ProcessDir(const bfs::path& dir) {
2002 // Prefer non-throwing versions of filesystem functions, since they are actually not unexpected
2003 // and because it's faster to use error codes.
2004 boost::system::error_code ec;
2005
2006 // Perform tilde expansion on incoming dir.
2007 const bfs::path expdir = SC_Filesystem::instance().expandTilde(dir);
2008
2009 // Using a recursive_directory_iterator is much faster than actually calling this function
2010 // recursively. Speedup from the switch was about 1.5x. _Do_ recurse on symlinks.
2011 bfs::recursive_directory_iterator rditer(expdir, bfs::symlink_option::recurse, ec);
2012
2013 // Check preconditions: are we able to access the file, and should we compile it according to
2014 // the language configuration?
2015 if (ec) {
2016 // If we got an error, post a warning if it was because the target wasn't found, and return success.
2017 // Otherwise, post the error and fail.
2018 if (ec.default_error_condition().value() == boost::system::errc::no_such_file_or_directory) {
2019 passOne_HandleMissingDirectory(expdir);
2020 return true;
2021 } else {
2022 error("Could not open directory '%s': (%d) %s\n", SC_Codecvt::path_to_utf8_str(expdir).c_str(), ec.value(),
2023 ec.message().c_str());
2024
2025 return false;
2026 }
2027 } else if (passOne_ShouldSkipDirectory(expdir)) {
2028 // If we should skip the directory, just return success now.
2029 return true;
2030 } else {
2031 // Let the user know we are in fact compiling this directory.
2032 post("\tCompiling directory '%s'\n", SC_Codecvt::path_to_utf8_str(expdir).c_str());
2033 }
2034
2035 // Record that we have touched this directory already.
2036 compiledDirectories.insert(expdir);
2037
2038 // Invariant: we have processed (or begun to process) every directory or file already
2039 // touched by the iterator.
2040 while (rditer != bfs::end(rditer)) {
2041 const bfs::path path = *rditer;
2042
2043 // If the file is a directory, perform the same checks as above to see if we should
2044 // skip compilation on it.
2045 if (bfs::is_directory(path)) {
2046 if (passOne_ShouldSkipDirectory(path)) {
2047 rditer.no_push(); // don't "push" into the next level of the hierarchy
2048 } else {
2049 // Mark this directory as compiled.
2050 // By not calling no_push(), we allow the iterator to enter the directory
2051 compiledDirectories.insert(path);
2052 }
2053
2054 } else { // ordinary file
2055 // Try to resolve a potential alias. Possible outcomes:
2056 // - it was an alias & is also a directory: try to recurse on it
2057 // - resolution failed: returns empty path: let the user know
2058 // - it was not an alias, or was an alias that wasn't a directory: try to process it as a source file
2059 bool isAlias = false;
2060 const bfs::path& respath = SC_Filesystem::resolveIfAlias(path, isAlias);
2061 if (isAlias && bfs::is_directory(respath)) {
2062 // If the resolved alias is a directory, recurse on it.
2063 if (!passOne_ProcessDir(respath)) {
2064 return false;
2065 }
2066 } else if (respath.empty()) {
2067 error("Could not resolve symlink: %s\n", SC_Codecvt::path_to_utf8_str(path).c_str());
2068 } else if (!passOne_ProcessOneFile(respath)) {
2069 return false;
2070 }
2071 }
2072
2073 // Error-code version of `++`
2074 rditer.increment(ec);
2075 if (ec) {
2076 // If iteration failed, allow compilation to continue, but bail out of this directory.
2077 error("Could not iterate on '%s': %s\n", SC_Codecvt::path_to_utf8_str(path).c_str(), ec.message().c_str());
2078 return true;
2079 }
2080 }
2081 return true;
2082 }
2083
passOne()2084 bool passOne() {
2085 initPassOne();
2086 bool success = gLanguageConfig->forEachIncludedDirectory(passOne_ProcessDir);
2087 finiPassOne();
2088
2089 return success;
2090 }
2091
2092 /// True if file doesn't begin with '.', and ends with either '.sc' or '.rtf'
isValidSourceFileName(const bfs::path & path)2093 bool isValidSourceFileName(const bfs::path& path) {
2094 const bfs::path& ext = path.extension();
2095 return path.filename().c_str()[0] != '.' && // must not be hidden file
2096 ((ext == ".sc") || (ext == ".rtf" && path.stem().extension() == ".sc"));
2097 }
2098
2099 /** \brief Attempt to parse a single SuperCollider source file
2100 *
2101 * Parsing is aborted if the file doesn't have a valid source file name,
2102 * or if the file can't be opened.
2103 * (Sekhar's replacement)
2104 *
2105 * \returns Whether parsing was successful. The only failure condition occurs
2106 * when the file can't be opened.
2107 */
passOne_ProcessOneFile(const bfs::path & path)2108 bool passOne_ProcessOneFile(const bfs::path& path) {
2109 bool success = true;
2110
2111 const std::string path_str = SC_Codecvt::path_to_utf8_str(path);
2112 const char* path_c_str = path_str.c_str();
2113 if (gLanguageConfig && gLanguageConfig->pathIsExcluded(path)) {
2114 post("\texcluding file: '%s'\n", path_c_str);
2115 return success;
2116 }
2117
2118 if (isValidSourceFileName(path)) {
2119 gNumCompiledFiles++;
2120 PyrSymbol* fileSym = getsym(path_c_str);
2121 fileSym->u.source = nullptr;
2122 if (startLexer(fileSym, path, -1, -1, -1)) {
2123 while (parseOneClass(fileSym)) {
2124 };
2125 finiLexer();
2126 } else {
2127 error("file '%s' open failed\n", path_c_str);
2128 success = false;
2129 }
2130 } else {
2131 // wasn't a valid source file; ignore
2132 }
2133 return success;
2134 }
2135
2136 void schedRun();
2137
2138 void compileSucceeded();
compileSucceeded()2139 void compileSucceeded() {
2140 compiledOK = !(parseFailed || compileErrors);
2141 if (compiledOK) {
2142 compiledOK = true;
2143
2144 compiledOK = initRuntime(gMainVMGlobals, 128 * 1024, pyr_pool_runtime);
2145
2146 if (compiledOK) {
2147 VMGlobals* g = gMainVMGlobals;
2148
2149 g->canCallOS = true;
2150
2151 ++g->sp;
2152 SetObject(g->sp, g->process);
2153 runInterpreter(g, s_startup, 1);
2154 g->canCallOS = false;
2155
2156 schedRun();
2157 }
2158 flushPostBuf();
2159 }
2160 }
2161
runShutdown()2162 static void runShutdown() {
2163 // printf("->aboutToCompileLibrary\n");
2164 gLangMutex.lock();
2165 if (compiledOK) {
2166 VMGlobals* g = gMainVMGlobals;
2167
2168 g->canCallOS = true;
2169
2170 ++g->sp;
2171 SetObject(g->sp, g->process);
2172 runInterpreter(g, s_shutdown, 1);
2173
2174 g->canCallOS = false;
2175 }
2176 gLangMutex.unlock();
2177 // printf("<-aboutToCompileLibrary\n");
2178 }
2179
2180 void closeAllGUIScreens();
2181 void TempoClock_stopAll(void);
2182 void closeAllCustomPorts();
2183
shutdownLibrary()2184 void shutdownLibrary() {
2185 closeAllGUIScreens();
2186
2187 schedStop();
2188
2189 runShutdown();
2190
2191 TempoClock_stopAll();
2192
2193 gLangMutex.lock();
2194 closeAllCustomPorts();
2195
2196 if (compiledOK) {
2197 VMGlobals* g = gMainVMGlobals;
2198 g->canCallOS = true;
2199 g->gc->RunAllFinalizers();
2200 g->canCallOS = false;
2201 }
2202
2203 pyr_pool_runtime->FreeAll();
2204
2205 compiledOK = false;
2206
2207 gLangMutex.unlock();
2208 deinitPrimitives();
2209
2210 SC_LanguageConfig::freeLibraryConfig();
2211 }
2212
compileLibrary(bool standalone)2213 SCLANG_DLLEXPORT_C bool compileLibrary(bool standalone) {
2214 // printf("->compileLibrary\n");
2215 shutdownLibrary();
2216
2217 gLangMutex.lock();
2218 gNumCompiledFiles = 0;
2219 compiledOK = false;
2220
2221 SC_LanguageConfig::readLibraryConfig(standalone);
2222
2223 compileStartTime = elapsedTime();
2224
2225 totalByteCodes = 0;
2226
2227 #ifdef NDEBUG
2228 postfl("compiling class library...\n");
2229 #else
2230 postfl("compiling class library (debug build)...\n");
2231 #endif
2232
2233 bool res = passOne();
2234 if (res) {
2235 if (!compileErrors) {
2236 buildDepTree();
2237 traverseFullDepTree();
2238 traverseFullDepTree2();
2239 flushPostBuf();
2240
2241 if (!compileErrors && gShowWarnings) {
2242 SymbolTable* symbolTable = gMainVMGlobals->symbolTable;
2243 symbolTable->CheckSymbols();
2244 }
2245 }
2246 pyr_pool_compile->FreeAll();
2247 flushPostBuf();
2248 compileSucceeded();
2249 } else {
2250 compiledOK = false;
2251 }
2252
2253 gLangMutex.unlock();
2254 // printf("<-compileLibrary\n");
2255 return compiledOK;
2256 }
2257
2258 void signal_init_globs();
2259
2260 void dumpByteCodes(PyrBlock* theBlock);
2261
runLibrary(PyrSymbol * selector)2262 SCLANG_DLLEXPORT_C void runLibrary(PyrSymbol* selector) {
2263 VMGlobals* g = gMainVMGlobals;
2264 g->canCallOS = true;
2265 try {
2266 if (compiledOK) {
2267 ++g->sp;
2268 SetObject(g->sp, g->process);
2269 runInterpreter(g, selector, 1);
2270 } else {
2271 postfl("Library has not been compiled successfully.\n");
2272 }
2273 } catch (std::exception& ex) {
2274 PyrMethod* meth = g->method;
2275 if (meth) {
2276 int ip = slotRawInt8Array(&meth->code) ? g->ip - slotRawInt8Array(&meth->code)->b : -1;
2277 post("caught exception in runLibrary %s:%s %3d\n",
2278 slotRawSymbol(&slotRawClass(&meth->ownerclass)->name)->name, slotRawSymbol(&meth->name)->name, ip);
2279 dumpByteCodes(meth);
2280 } else {
2281 post("caught exception in runLibrary\n");
2282 }
2283 error(ex.what());
2284 } catch (...) {
2285 postfl("DANGER: OUT of MEMORY. Operation failed.\n");
2286 }
2287 g->canCallOS = false;
2288 }
2289