gscheme/VScheme.m

2101 lines
57 KiB
Mathematica
Raw Normal View History

2022-08-05 05:28:40 -04:00
#import "VScheme.h"
#import "SchemeDelegate.h"
2022-08-05 05:28:41 -04:00
/* #include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h> */
extern id yyresultform;
extern BOOL yyschemeerrflag;
NSMutableArray *positionStack = nil;
2022-08-05 05:28:40 -04:00
static char *forms[] = {
"top",
"define1", "define2", "set",
"lambda1", "lambda2",
"quote", "binding",
"let", "let*", "letrec",
"if1", "if2",
"and", "or",
"begin", "apply",
"case", "scond1", "scond2", "scond3", "cond",
"callcc"
};
void print_tree(id item, int indent)
{
int pos;
for(pos=0; pos<indent; pos++){
putchar(' ');
}
if(item==[NSNull null]){
puts("'()");
}
else if([item isKindOfClass:[Boolean class]]){
printf("BOOL: %s\n", (![item boolVal] ? "NO" : "YES"));
}
else if([item isKindOfClass:[Char class]]){
char c = [item charVal];
if(c=='\n'){
printf("CHAR: <\\newline>\n");
}
else if(c=='\t'){
printf("CHAR: <\\tab>\n");
}
else if(c==' '){
printf("CHAR: <\\space>\n");
}
else{
printf("CHAR: <%c>\n", c);
}
}
else if([item isKindOfClass:[Int class]]){
printf("INT: %ld\n", [item intVal]);
}
else if([item isKindOfClass:[Double class]]){
printf("DOUBLE: %le\n", [item doubleVal]);
}
else if([item isKindOfClass:[Symbol class]]){
printf("SYMBOL: <%s>\n", [[item symVal] cString]);
}
else if([item isKindOfClass:[String class]]){
printf("STRING: <%s>\n", [[item strVal] cString]);
}
else if([item isKindOfClass:[Closure class]]){
printf("CLOSURE %s\n",
[[VScheme valToString:[item args]] cString]);
}
else if([item isKindOfClass:[Primitive class]]){
printf("PRIMITIVE\n");
}
else if([item isKindOfClass:[Thunk class]]){
printf("THUNK %d %d %d\n", [item argp], [item envp], [item codep]);
}
else if([item isKindOfClass:[Pair class]]){
printf("PAIR %s\n", [[VScheme valToString:item] cString]);
}
else if([item isKindOfClass:[Vector class]]){
2022-08-05 05:28:41 -04:00
printf("VECTOR %s\n", [[VScheme valToString:item] cString]);
2022-08-05 05:28:40 -04:00
}
else if([item isKindOfClass:[ByteCodes class]]){
2022-08-05 05:28:41 -04:00
printf("CODES: %u\n", [item length]);
2022-08-05 05:28:40 -04:00
}
else{
printf("FORM %s\n", forms[[item tag]]);
if([item arg1]!=nil){
print_tree([item arg1], indent+1);
}
if([item arg2]!=nil){
print_tree([item arg2], indent+1);
}
if([item arg3]!=nil){
print_tree([item arg3], indent+1);
}
}
}
void print_scheme_item(id item)
{
print_tree(item, 0);
}
@implementation VScheme
static char *codenames[] = {
"TO_ARGS",
"LOOKUP",
"CHECK_PTC",
"POP_ENV",
"POP_ARGS",
"APPLIC",
"LIST_APPLIC",
"DEFINE",
"SET",
"CLOSURE",
"IF",
"LAYER",
"MEMQ",
"DUP_ARG",
"EXCH_ARGS",
"STATE_TO_THUNK",
"MARK_THUNK"
};
+ (NSString *)valToString:(id)item seen:(NSMutableSet *)mem
{
if(item==[NSNull null]){
return @"()";
}
if((isPair(item) || isVector(item)) &&
[mem containsObject:item]==YES){
return @"<circular>";
}
if(isBoolean(item)){
return ([item boolVal]==YES ? @"#t" : @"#f");
}
else if(isChar(item)){
NSString *format;
char c = [item charVal];
if(c=='\n'){
format = @"#\\newline";
}
else if(c=='\t'){
format = @"#\\tab";
}
else if(c==' '){
format = @"#\\space";
}
else{
format = @"#\\%c";
}
2022-08-05 05:28:41 -04:00
return [NSString stringWithFormat:format, c];
2022-08-05 05:28:40 -04:00
}
else if(isInt(item)){
2022-08-05 05:28:41 -04:00
return [NSString stringWithFormat:@"%d", [item intVal]];
2022-08-05 05:28:40 -04:00
}
else if(isDouble(item)){
2022-08-05 05:28:41 -04:00
double v = [item doubleVal];
NSString *vstr = [[NSNumber numberWithDouble:v] description];
const char *buf = [vstr cString];
if(*buf && *buf=='-'){
buf++;
}
while(*buf && isdigit(*buf++));
if(!(*buf)){
vstr = [vstr stringByAppendingString:@".0"];
}
return vstr;
2022-08-05 05:28:40 -04:00
}
else if(isSymbol(item)){
2022-08-05 05:28:41 -04:00
return [NSString stringWithFormat:@"%@", [item symVal]];
2022-08-05 05:28:40 -04:00
}
else if(isString(item)){
2022-08-05 05:28:41 -04:00
NSString *str = [item strVal];
int len = [str length];
const char *src;
char buf[2*len+1], *dst;
src = [str cString]; dst = buf;
while(*src){
if(*src=='"'){
*dst++ = '\\';
}
*dst++ = *src++;
}
*dst = 0;
return [NSString stringWithFormat:@"\"%s\"", buf];
2022-08-05 05:28:40 -04:00
}
else if(isClosure(item)){
2022-08-05 05:28:41 -04:00
return [NSString
stringWithFormat:@"<closure: %@>",
2022-08-05 05:28:40 -04:00
[VScheme valToString:[item args] seen:mem]];
}
else if(isPrimitive(item)){
2022-08-05 05:28:41 -04:00
return [NSString
stringWithFormat:@"<primitive: %@>",
[item primName]];
2022-08-05 05:28:40 -04:00
}
else if(isThunk(item)){
2022-08-05 05:28:41 -04:00
return [NSString
stringWithFormat:@"<thunk: %d %d %d>",
[item argp], [item envp], [item codep]];
2022-08-05 05:28:40 -04:00
}
else if(isPair(item)){
NSString *str;
NSMutableSet *local = [NSMutableSet setWithCapacity:1];
NSEnumerator *en;
[mem addObject:item]; [local addObject:item];
str = [VScheme valToString:[item car] seen:mem];
item = [item cdr];
while(isPair(item) && [mem containsObject:item]==NO){
[mem addObject:item]; [local addObject:item];
str = [str stringByAppendingFormat:@" %@",
[VScheme valToString:[item car] seen:mem]];
item = [item cdr];
}
if(isPair(item)){
str = [str stringByAppendingString:@" <circular>"];
}
else if(item!=[NSNull null]){
str = [str stringByAppendingFormat:@" . %@",
[VScheme valToString:item seen:mem]];
}
en = [local objectEnumerator];
while((item = [en nextObject])!=nil){
[mem removeObject:item];
}
[local removeAllObjects];
return [NSString stringWithFormat:@"(%@)", str];
}
else if(isVector(item)){
id *entries = [item entries];
NSString *str;
int count = [item count], index;
if(!count){
return @"#()";
}
[mem addObject:item];
str = [NSString stringWithFormat:@"#(%@",
[VScheme valToString:entries[0] seen:mem]];
for(index=1; index<count; index++){
str = [str stringByAppendingFormat:@" %@",
[VScheme valToString:entries[index] seen:mem]];
}
str = [str stringByAppendingString:@")"];
[mem removeObject:item];
return str;
}
else{
return [[NSString alloc] initWithFormat:@"%@"
locale: nil, item];
}
}
+ (NSString *)valToString:(id)item
{
NSMutableSet *mem = [NSMutableSet setWithCapacity:1];
return [VScheme valToString:item seen:mem];
}
+ printInstr:(Triple *)instr
{
int tag;
tag = [instr tag];
if(0<= tag && tag<INSTR_COUNT){
printf("%s\n", codenames[[instr tag]]);
}
switch(tag){
case IN_TO_ARGS:
print_scheme_item([instr arg1]);
break;
case IN_LOOKUP:
case IN_CHECK_PTC:
case IN_LIST_APPLIC:
case IN_DUP_ARG:
case IN_EXCH_ARGS:
break;
case IN_STATE_TO_THUNK:
case IN_MARK_THUNK: {
Thunk *t = [instr arg1];
printf("%d %d %d", [t argp], [t envp], [t codep]);
} break;
case IN_POP_ENV:
case IN_POP_ARGS:
case IN_APPLIC:
case IN_LAYER:
printf("%d", [instr intarg1]);
break;
case IN_DEFINE:
case IN_SET:
case IN_CLOSURE:
case IN_MEMQ:
break;
case IN_IF:
print_scheme_item([instr arg1]);
print_scheme_item([instr arg2]);
break;
default:
printf("tag out of range: %d\n", tag);
}
putchar('\n');
return self;
}
2022-08-05 05:28:41 -04:00
+ printCodes:(ByteCodes *)bc
2022-08-05 05:28:40 -04:00
{
2022-08-05 05:28:41 -04:00
id *data = [bc codes];
2022-08-05 05:28:40 -04:00
2022-08-05 05:28:41 -04:00
unsigned int pos, len = [bc length];
for(pos=0; pos<len; pos++){
[self printInstr:data[pos]];
2022-08-05 05:28:40 -04:00
}
return self;
}
- init
{
[super init];
codeStack = nil;
pcStack = nil;
argStack = nil;
envStack = nil;
output = nil;
[self reset:self];
return self;
}
- delegate
{
return delegate;
}
- setDelegate:(id)aDelegate
{
delegate = aDelegate;
return self;
}
- resetStacks;
{
if(codeStack!=nil){
[codeStack release];
codeStack = nil;
}
if(pcStack!=nil){
[pcStack release];
pcStack = nil;
}
if(argStack!=nil){
[argStack release];
argStack = nil;
}
maxcode = 0;
maxpc = 0;
maxarg = 0;
maxenv = 0;
return self;
}
#define LIB @"library.scm"
- reset:(id)sender
{
NSString *msg = nil;
NSFileManager *manager = [NSFileManager defaultManager];
NSString *fileName;
2022-08-05 05:28:41 -04:00
if(errmsg != nil &&
[errmsg isKindOfClass:[NSConstantString class]]==NO){
[errmsg release];
}
2022-08-05 05:28:40 -04:00
errflag = NO;
errmsg = @"";
[self resetStacks];
[self clearOutput];
[self clearImage];
if(envStack!=nil){
[envStack release];
envStack = nil;
}
[self makeStartEnvironment];
fileName = [[[NSBundle mainBundle] bundlePath]
stringByAppendingPathComponent:@"Resources"];
fileName = [fileName stringByAppendingPathComponent:LIB];
if([manager fileExistsAtPath:fileName]==NO){
msg = [NSString
stringWithFormat:@"Library not found: %@",
fileName];
}
else{
NSString *str = [NSString stringWithContentsOfFile:fileName];
if(str==nil){
msg = [NSString
stringWithFormat:@"Couldn't load library: %@",
fileName];
}
if([self processString:str mode:MODE_LOAD]==NO){
msg = errmsg;
}
}
if(msg!=nil){
NSRunAlertPanel(@"Error (load library)", msg, @"Ok", nil, nil);
}
return self;
}
- appendToOutput:(NSString *)data
{
2022-08-05 05:28:41 -04:00
[output appendString:data];
2022-08-05 05:28:40 -04:00
return self;
}
- (NSString *)output
{
return output;
}
- clearOutput
{
if(output!=nil){
[output release];
}
2022-08-05 05:28:41 -04:00
output = [NSMutableString stringWithCString:""]; // @"";
2022-08-05 05:28:40 -04:00
[output retain];
return self;
}
2022-08-05 05:28:41 -04:00
#define FONTSIZE 12.0
- (NSSize)stringAtCurrentFont:(NSString *)str
{
NSFont *font =
(imgFont==nil ? [NSFont systemFontOfSize:FONTSIZE] : imgFont);
NSDictionary *attr =
[NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
return [str sizeWithAttributes:attr];
}
2022-08-05 05:28:40 -04:00
- recordImgInst:(DrawInst)inst
{
NSValue *entry =
[NSValue valueWithBytes:&inst objCType:@encode(DrawInst)];
2022-08-05 05:28:41 -04:00
if(atImgStart==YES && (inst.what==DRAW_MOVE || inst.what==DRAW_LINE)){
atImgStart = NO;
imgMin = imgMax = imgCur = inst.data.coord;
}
else if(atImgStart==YES && (inst.what==DRAW_CIRCLE || inst.what==FILL_CIRCLE)){
atImgStart = NO;
imgMin.x = -inst.data.radius;
imgMax.x = inst.data.radius;
imgMin.y = -inst.data.radius;
imgMax.y = inst.data.radius;
imgCur = NSMakePoint(0, 0);
}
else if(atImgStart==YES && (inst.what==DRAW_RECT || inst.what==FILL_RECT)){
2022-08-05 05:28:40 -04:00
atImgStart = NO;
2022-08-05 05:28:41 -04:00
imgMin.x = 0;
imgMax.x = inst.data.size.width;
imgMin.y = 0;
imgMax.y = inst.data.size.height;
imgCur = NSMakePoint(0, 0);
2022-08-05 05:28:40 -04:00
}
2022-08-05 05:28:41 -04:00
else if(atImgStart==YES && inst.what==DRAW_STRING){
atImgStart = NO;
imgMin = NSMakePoint(0, 0);
NSSize result = [self stringAtCurrentFont:inst.data.string];
imgMax.x = result.width;
imgMax.y = result.height;
imgCur = NSMakePoint(result.width, 0);
}
else if(inst.what==DRAW_MOVE || inst.what==DRAW_LINE){
2022-08-05 05:28:40 -04:00
if(imgMin.x>inst.data.coord.x){
imgMin.x = inst.data.coord.x;
}
if(imgMin.y>inst.data.coord.y){
imgMin.y = inst.data.coord.y;
}
if(imgMax.x<inst.data.coord.x){
imgMax.x = inst.data.coord.x;
}
if(imgMax.y<inst.data.coord.y){
imgMax.y = inst.data.coord.y;
}
2022-08-05 05:28:41 -04:00
imgCur = inst.data.coord;
}
else if(inst.what==DRAW_CIRCLE || inst.what==FILL_CIRCLE){
float
minx = imgCur.x-inst.data.radius,
miny = imgCur.y-inst.data.radius,
maxx = imgCur.x+inst.data.radius,
maxy = imgCur.y+inst.data.radius;
if(imgMin.x>minx){
imgMin.x = minx;
}
if(imgMin.y>miny){
imgMin.y = miny;
}
if(imgMax.x<maxx){
imgMax.x = maxx;
}
if(imgMax.y<maxy){
imgMax.y = maxy;
}
}
else if(inst.what==DRAW_RECT || inst.what==FILL_RECT){
float
maxx = imgCur.x+inst.data.size.width,
maxy = imgCur.y+inst.data.size.height;
if(imgMax.x<maxx){
imgMax.x = maxx;
}
if(imgMax.y<maxy){
imgMax.y = maxy;
}
}
else if(inst.what==DRAW_STRING){
NSSize result = [self stringAtCurrentFont:inst.data.string];
if(imgMax.x<imgCur.x+result.width){
imgMax.x = imgCur.x+result.width;
}
if(imgMax.y<imgCur.y+result.height){
imgMax.y=imgCur.y+result.height;
}
imgCur.x += result.width;
}
else if(inst.what==DRAW_FONT){
imgFont = inst.data.font;
2022-08-05 05:28:40 -04:00
}
[imgCodes addObject:entry];
}
- clearImage
{
atImgStart = YES;
2022-08-05 05:28:41 -04:00
imgFont = nil;
2022-08-05 05:28:40 -04:00
if(imgCodes!=nil){
[imgCodes release];
imgCodes = nil;
}
imgCodes = [NSMutableArray arrayWithCapacity:1];
[imgCodes retain];
}
#define PAD ((float)10)
static int imgCount = 0;
#define BASEX 200
#define BASEY 200
#define WDELTA 10
#define WREP 12
- produceImage
{
NSSize imgSize;
NSRect imgRect;
NSRect frame;
int index;
NSWindow *window;
NSImageView *view;
NSImage *img;
NSColor *col;
int m = (NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask);
imgMin.x -= PAD; imgMin.y -= PAD;
imgMax.x += PAD; imgMax.y += PAD;
imgRect.origin.x = 0;
imgRect.origin.y = 0;
imgRect.size.width = imgMax.x-imgMin.x;
imgRect.size.height = imgMax.y-imgMin.y;
img = [[NSImage alloc] initWithSize:imgRect.size];
view = [[SCMImageView alloc] initWithFrame:imgRect];
[img lockFocus];
2022-08-05 05:28:41 -04:00
[[NSFont systemFontOfSize:FONTSIZE] set];
2022-08-05 05:28:40 -04:00
[[NSColor whiteColor] set];
PSrectfill(0, 0, imgRect.size.width, imgRect.size.height);
PStranslate(-imgMin.x, -imgMin.y);
2022-08-05 05:28:41 -04:00
[[NSColor blackColor] set];
imgCur = NSMakePoint(0, 0);
imgFont = nil;
2022-08-05 05:28:40 -04:00
for(index=0; index<[imgCodes count]; index++){
NSValue *entry = [imgCodes objectAtIndex:index];
DrawInst inst;
[entry getValue:&inst];
if(inst.what==DRAW_MOVE){
PSmoveto(inst.data.coord.x, inst.data.coord.y);
2022-08-05 05:28:41 -04:00
imgCur = inst.data.coord;
2022-08-05 05:28:40 -04:00
}
else if(inst.what==DRAW_LINE){
PSlineto(inst.data.coord.x, inst.data.coord.y);
2022-08-05 05:28:41 -04:00
imgCur = inst.data.coord;
2022-08-05 05:28:40 -04:00
}
2022-08-05 05:28:41 -04:00
else if(inst.what==DRAW_CIRCLE){
PSstroke();
PSarc(imgCur.x, imgCur.y, inst.data.radius, 0, 360);
PSstroke();
PSmoveto(imgCur.x, imgCur.y);
}
else if(inst.what==FILL_CIRCLE){
PSstroke();
PSarc(imgCur.x, imgCur.y, inst.data.radius, 0, 360);
PSfill();
PSmoveto(imgCur.x, imgCur.y);
}
else if(inst.what==DRAW_RECT){
PSstroke();
NSFrameRect(NSMakeRect(imgCur.x, imgCur.y,
inst.data.size.width, inst.data.size.height));
PSmoveto(imgCur.x, imgCur.y);
}
else if(inst.what==FILL_RECT){
PSstroke();
NSRectFill(NSMakeRect(imgCur.x, imgCur.y,
inst.data.size.width, inst.data.size.height));
PSmoveto(imgCur.x, imgCur.y);
}
else if(inst.what==DRAW_STRING){
PSmoveto(imgCur.x, imgCur.y);
PSshow([inst.data.string cString]);
PSstroke();
NSSize result = [self stringAtCurrentFont:inst.data.string];
imgCur.x += result.width;
PSmoveto(imgCur.x, imgCur.y);
[inst.data.string release];
}
else if(inst.what==DRAW_FONT){
if(imgFont!=nil){
[imgFont release];
}
imgFont = inst.data.font;
[imgFont set];
}
2022-08-05 05:28:40 -04:00
else{
PSstroke();
col = [NSColor colorWithDeviceRed:inst.data.color[0]
green:inst.data.color[1]
blue:inst.data.color[2]
alpha:1.0];
[col set];
}
}
PSstroke();
[img unlockFocus];
2022-08-05 05:28:41 -04:00
if(imgFont!=nil){
[imgFont release];
}
2022-08-05 05:28:40 -04:00
[view setImage:img];
frame = [NSWindow frameRectForContentRect:[view frame]
styleMask:m];
frame.origin.x = BASEX + (imgCount%WREP)*WDELTA;
frame.origin.y = BASEY + (imgCount%WREP)*WDELTA;
window = [[NSWindow alloc] initWithContentRect:frame
styleMask:m
2022-08-05 05:28:41 -04:00
backing: NSBackingStoreNonretained
2022-08-05 05:28:40 -04:00
defer:YES];
[window setMinSize:frame.size];
[window setTitle:
[NSString
stringWithFormat:@"Image #%d", ++imgCount]];
[window setFrame:frame display:YES];
[window setMaxSize:frame.size];
[window setContentView:view];
[window setReleasedWhenClosed:YES];
// [window setDelegate:view];
// RELEASE(view);
[window orderFront:nil];
[window display];
2022-08-05 05:28:41 -04:00
[delegate imageWindow:window];
2022-08-05 05:28:40 -04:00
return window;
}
- (int)maxcode
{
return maxcode;
}
- (int)maxpc
{
return maxpc;
}
- (int)maxarg
{
return maxarg;
}
- (int)maxenv
{
return maxenv;
}
- makeStartEnvironment
{
Environment *env;
void *state = NULL;
Class primcls[] = {
[PRMPairPred class],
[PRMNullPred class],
[PRMZeroPred class],
[PRMNumberPred class],
[PRMEqPred class],
[PRMNot class],
[PRMNumEqual class],
[PRMNumLT class],
[PRMNumGT class],
[PRMPlus class],
[PRMTimes class],
[PRMMinus class],
[PRMDivide class],
2022-08-05 05:28:41 -04:00
[PRMRandom class],
2022-08-05 05:28:40 -04:00
[PRMQuotient class],
[PRMRemainder class],
[PRMList class],
[PRMCons class],
[PRMCar class],
[PRMCdr class],
[PRMSetCar class],
[PRMSetCdr class],
[PRMDisplay class],
[PRMNewline class],
[PRMDrawMove class],
[PRMDrawLine class],
[PRMDrawColor class],
2022-08-05 05:28:41 -04:00
[PRMDrawCircle class],
[PRMFillCircle class],
[PRMDrawRect class],
[PRMFillRect class],
[PRMDrawString class],
[PRMDrawFont class],
[PRMDrawShow class],
[PRMExp class],
[PRMLog class],
2022-08-05 05:28:40 -04:00
[PRMSin class],
[PRMASin class],
[PRMCos class],
[PRMACos class],
2022-08-05 05:28:41 -04:00
[PRMTan class],
[PRMATan class],
2022-08-05 05:28:40 -04:00
[PRMSqrt class],
[PRMMakeVector class],
[PRMVectorPred class],
[PRMListToVector class],
[PRMVectorToList class],
[PRMVectorLength class],
[PRMVectorRef class],
[PRMVectorSet class],
[PRMVectorFill class],
2022-08-05 05:28:41 -04:00
[PRMSymToStr class],
[PRMStrToSym class],
[PRMStringSize class],
[PRMStringLength class],
[PRMCharToInt class],
[PRMIntToChar class],
[PRMStringRef class],
[PRMListToStr class],
[PRMStrToList class],
[PRMNumberToStr class],
[PRMStringAppend class],
[PRMMakeString class],
[PRMFormat class],
[PRMEval class],
2022-08-05 05:28:40 -04:00
[PRMBrowseEnvironment class],
nil
}, *current, cl;
id primitive;
2022-08-05 05:28:41 -04:00
NSMapTable
*prim = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSNonRetainedObjectMapValueCallBacks, 1),
*glob = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSNonRetainedObjectMapValueCallBacks, 1);
2022-08-05 05:28:40 -04:00
current = primcls;
while((cl = *current++) != nil){
2022-08-05 05:28:41 -04:00
primitive = [[cl alloc] init]; [primitive retain];
NSMapInsert(prim, [primitive primName], primitive);
2022-08-05 05:28:40 -04:00
}
env = [Environment newParent:nil Data:prim];
env = [Environment newParent:env Data:glob];
envStack = [NSMutableArray arrayWithCapacity:1];
2022-08-05 05:28:41 -04:00
[envStack addObject:env];
2022-08-05 05:28:40 -04:00
[envStack retain];
return self;
}
- (NSMutableArray *)argStack
{
return argStack;
}
- (NSMutableArray *)envStack
{
return envStack;
}
- (NSMutableArray *)codeStack
{
return codeStack;
}
- (BOOL)errflag
{
return errflag;
}
2022-08-05 05:28:41 -04:00
- (int)errpos
{
return errpos;
}
2022-08-05 05:28:40 -04:00
- (NSString *)errmsg
{
return errmsg;
}
- args2list:(int)lower
{
int pos = [argStack count]-1;
id res = [NSNull null];
while(pos>=lower){
res = [Pair newCar:[argStack objectAtIndex:pos]
Cdr:res];
pos--;
}
return res;
}
2022-08-05 05:28:41 -04:00
- pushByteCodes:(ByteCodes *)bcodes
2022-08-05 05:28:40 -04:00
{
2022-08-05 05:28:41 -04:00
if(curpc==curlength){
2022-08-05 05:28:40 -04:00
[codeStack removeLastObject];
}
else{
2022-08-05 05:28:41 -04:00
[pcStack addObject:[NSNumber numberWithInt:curpc]];
2022-08-05 05:28:40 -04:00
}
2022-08-05 05:28:41 -04:00
[codeStack addObject:bcodes];
curpc = 0; curcodes = [bcodes codes]; curlength = [bcodes length];
2022-08-05 05:28:40 -04:00
2022-08-05 05:28:41 -04:00
return self;
}
2022-08-05 05:28:40 -04:00
2022-08-05 05:28:41 -04:00
- interrupt:(id)sender
{
interrupted = YES;
2022-08-05 05:28:40 -04:00
return self;
}
2022-08-05 05:28:41 -04:00
#define INITIALINT 5
#define INTERVAL 1
2022-08-05 05:28:40 -04:00
2022-08-05 05:28:41 -04:00
- (BOOL)run:(ByteCodes *)prog mode:(PROCESS_MODE)pmode;
2022-08-05 05:28:40 -04:00
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
id instr;
2022-08-05 05:28:41 -04:00
if(errmsg != nil &&
[errmsg isKindOfClass:[NSConstantString class]]==NO){
[errmsg release];
errmsg = @"";
}
2022-08-05 05:28:40 -04:00
codeStack = [NSMutableArray arrayWithCapacity:1];
pcStack = [NSMutableArray arrayWithCapacity:1];
argStack = [NSMutableArray arrayWithCapacity:1];
[codeStack retain];
[pcStack retain];
[argStack retain];
2022-08-05 05:28:41 -04:00
[codeStack addObject:prog];
[prog setRoot:YES];
2022-08-05 05:28:40 -04:00
curcodes = [prog codes];
2022-08-05 05:28:41 -04:00
curpc = 0; curlength = [prog length];
NSApplication *app = [NSApplication sharedApplication];
BOOL inModal = NO;
NSDate *interruptDate = [NSDate dateWithTimeIntervalSinceNow:INITIALINT];
NSModalSession interruptSession;
NSPanel *interruptPanel = [delegate interruptPanel];
int interruptMask = NSLeftMouseDownMask | NSLeftMouseUpMask |
NSLeftMouseDraggedMask;
hadOutput = NO;
interrupted = NO;
[interruptDate retain];
2022-08-05 05:28:40 -04:00
2022-08-05 05:28:41 -04:00
/* struct rusage usg;
getrusage(RUSAGE_SELF, &usg);
long start = usg.ru_utime.tv_sec; */
#define RESFORITER 4000
unsigned long int iterations = 0;
2022-08-05 05:28:40 -04:00
while(1){
2022-08-05 05:28:41 -04:00
iterations++;
if(!(iterations % RESFORITER) && pmode!=MODE_LOAD && inModal==NO &&
[interruptDate timeIntervalSinceNow]<0.0){
[interruptPanel center];
[interruptPanel orderOut:nil];
[interruptPanel flushWindow];
interruptSession = [app beginModalSessionForWindow:interruptPanel];
inModal = YES;
[interruptDate release];
interruptDate = [NSDate dateWithTimeIntervalSinceNow:INTERVAL];
[interruptDate retain];
[[NSCursor arrowCursor] push];
}
else if(!(iterations % RESFORITER) && inModal==YES &&
[interruptDate timeIntervalSinceNow]<0.0){
NSDate *evDate = [NSDate dateWithTimeIntervalSinceNow:0.025];
NSEvent *event =
[app nextEventMatchingMask:interruptMask
untilDate:evDate
inMode:NSDefaultRunLoopMode
dequeue:YES];
if([event window]==interruptPanel){
[app sendEvent:event];
}
if(interrupted==YES){
errflag = YES;
errmsg = @"user abort";
break;
}
else{
[interruptDate release];
interruptDate = [NSDate dateWithTimeIntervalSinceNow:INTERVAL];
[interruptDate retain];
if(output!=nil){
if(hadOutput==NO){
[delegate output:@"\n"];
hadOutput = YES;
}
[delegate output:output];
[self clearOutput];
}
}
}
if(!(curpc<curlength)){
2022-08-05 05:28:40 -04:00
[codeStack removeLastObject];
if(![codeStack count]){
break;
}
2022-08-05 05:28:41 -04:00
ByteCodes *bc = [codeStack lastObject];
curcodes = [bc codes];
curpc = [[pcStack lastObject] intValue]; curlength = [bc length];
2022-08-05 05:28:40 -04:00
[pcStack removeLastObject];
}
// printf("-%d-%d- ", [codeStack count], curpc);
2022-08-05 05:28:41 -04:00
instr = curcodes[curpc++];
2022-08-05 05:28:40 -04:00
// [VScheme printInstr:instr];
switch([instr tag]){
case IN_TO_ARGS:
2022-08-05 05:28:41 -04:00
[argStack addObject:[instr arg1]];
2022-08-05 05:28:40 -04:00
break;
case IN_LOOKUP:{
NSString *sym = [[argStack lastObject] symVal];
2022-08-05 05:28:41 -04:00
NSMapTable *layer =
2022-08-05 05:28:40 -04:00
[[envStack lastObject] lookup:sym];
2022-08-05 05:28:41 -04:00
if(layer==NULL){
2022-08-05 05:28:40 -04:00
errflag = YES;
errmsg =
[[NSString alloc]
2022-08-05 05:28:41 -04:00
initWithFormat:@"symbol %@ not bound", sym];
2022-08-05 05:28:40 -04:00
}
else{
[argStack removeLastObject];
2022-08-05 05:28:41 -04:00
[argStack addObject:NSMapGet(layer, sym)];
2022-08-05 05:28:40 -04:00
}
} break;
case IN_CHECK_PTC:{
id item = [argStack lastObject];
if(!(isPrimitive(item) || isClosure(item) ||
isThunk(item))){
NSString *format =
2022-08-05 05:28:41 -04:00
@"primitive, thunk or closure required, got %@ (%@)";
2022-08-05 05:28:40 -04:00
errflag = YES;
errmsg =
[[NSString alloc]
2022-08-05 05:28:41 -04:00
initWithFormat:format,
NSStringFromClass([item class]),
[VScheme valToString:item]];
2022-08-05 05:28:40 -04:00
}
} break;
case IN_POP_ENV:{
int count = [instr intarg1];
while(count--){
[envStack removeLastObject];
}
} break;
case IN_POP_ARGS:{
int count = [instr intarg1];
while(count--){
[argStack removeLastObject];
}
} break;
case IN_LIST_APPLIC:{
id list = [argStack lastObject];
int argc = 0;
[argStack removeLastObject];
while(isPair(list)){
2022-08-05 05:28:41 -04:00
[argStack addObject:[list car]];
2022-08-05 05:28:40 -04:00
list = [list cdr];
argc++;
}
if(list!=[NSNull null]){
errflag = YES;
errmsg = @"second arg to apply not a proper list";
break;
}
[instr setIntArg1:argc];
}
case IN_APPLIC:{
int argc = [instr intarg1];
int offs = [argStack count]-argc;
id op = [argStack objectAtIndex:(offs-1)];
id res = nil;
2022-08-05 05:28:41 -04:00
if(isEval(op)){
if(offs+1!=[argStack count]){
errflag = YES;
errmsg = @"eval takes one argument";
break;
}
NSString *evStr =
[VScheme valToString:[argStack objectAtIndex:offs]];
[self parse:evStr];
if(yyschemeerrflag==YES){
#define MAXL 40
char buf[MAXL+1];
[evStr getCString:buf maxLength:MAXL];
errflag = YES;
errmsg = [[NSString alloc]
initWithFormat:@"parse error in %s%s.",
buf, ([evStr length]>MAXL ? " (...)" : "")];
break;
}
[positionStack removeLastObject];
id evForms = yyresultform;
if(evForms==[NSNull null]){
res = [NSNull null];
break;
}
// [SCMType addToMarkables:evForms];
ByteCodes *evCodes = [ByteCodes new];
[evCodes setSource:evForms];
errflag = [self compile:[evForms arg1] output:evCodes];
if(errflag==NO){
[evCodes setRoot:YES];
[self pushByteCodes:evCodes];
}
}
else if(isPrimitive(op)){
2022-08-05 05:28:40 -04:00
if([op evalVM:self Args:argStack offset:offs]==YES){
res = [op value];
}
else{
errflag = YES;
2022-08-05 05:28:41 -04:00
errmsg =
[[NSString alloc]
initWithString:[(Primitive *)op errmsg]];
2022-08-05 05:28:40 -04:00
break;
}
}
else if(isThunk(op)){
int
argp = [op argp],
envp = [op envp],
codep = [op codep],
curargp = [argStack count],
curenvp = [envStack count],
curcodep = [codeStack count];
if(argp<0 || envp<0 || codep<0){
errflag = YES;
errmsg = @"this thunk has expired";
break;
}
if(argc!=1){
errflag = YES;
errmsg = @"thunk requires a single argument";
break;
}
res = [argStack lastObject];
while(curargp-->argp){
[argStack removeLastObject];
}
while(curenvp-->envp){
[envStack removeLastObject];
}
while(curcodep-->codep){
[codeStack removeLastObject];
if(curcodep>codep){
[pcStack removeLastObject];
}
}
curpc = [[pcStack lastObject] intValue];
[pcStack removeLastObject];
2022-08-05 05:28:41 -04:00
curcodes = [[codeStack lastObject] codes];
2022-08-05 05:28:40 -04:00
}
else if(isClosure(op)){
2022-08-05 05:28:41 -04:00
NSMapTable *layer =
NSCreateMapTable(NSObjectMapKeyCallBacks,
NSNonRetainedObjectMapValueCallBacks, 1);
2022-08-05 05:28:40 -04:00
id argl = [op args];
id env;
if(isSymbol(argl)){
2022-08-05 05:28:41 -04:00
id list = [self args2list:offs]; [list retain];
NSMapInsert(layer, [argl symVal], list);
2022-08-05 05:28:40 -04:00
}
else{
int symc = 0;
while(isPair(argl)){
symc++;
if(symc>argc){
errflag = YES;
2022-08-05 05:28:41 -04:00
errmsg =
[[NSString alloc]
initWithFormat:@"not enough arguments to %@",
[VScheme valToString:op]];
2022-08-05 05:28:40 -04:00
break;
}
2022-08-05 05:28:41 -04:00
id obj = [argStack objectAtIndex:offs++]; [obj retain];
NSMapInsert(layer, [[argl car] symVal], obj);
2022-08-05 05:28:40 -04:00
argl = [argl cdr];
}
if(symc<argc && argl==[NSNull null]){
errflag = YES;
2022-08-05 05:28:41 -04:00
errmsg =
[[NSString alloc]
initWithFormat:@"too many arguments to %@",
[VScheme valToString:op]];
2022-08-05 05:28:40 -04:00
break;
}
if(errflag==NO && argl!=[NSNull null]){
2022-08-05 05:28:41 -04:00
id list = [self args2list:offs]; [list retain];
NSMapInsert(layer, [argl symVal], list);
2022-08-05 05:28:40 -04:00
}
}
env = [Environment newParent:[op env] Data:layer];
2022-08-05 05:28:41 -04:00
[envStack addObject:env];
[self pushByteCodes:[op body]];
2022-08-05 05:28:40 -04:00
}
if(isThunk(op)==NO){
while(argc--){
[argStack removeLastObject];
}
[argStack removeLastObject];
}
if(res!=nil){
2022-08-05 05:28:41 -04:00
[argStack addObject:res];
2022-08-05 05:28:40 -04:00
}
} break;
case IN_DEFINE:{
int offs = [argStack count]-2;
2022-08-05 05:28:41 -04:00
NSMapTable *layer =
[(Environment *)[envStack lastObject] data];
id obj = [argStack objectAtIndex:(offs+1)]; [obj retain];
NSMapInsert(layer, [[argStack objectAtIndex:offs] symVal], obj);
2022-08-05 05:28:40 -04:00
[argStack removeLastObject];
} break;
case IN_SET:{
int offs = [argStack count]-2;
NSString *sym = [[argStack objectAtIndex:offs] symVal];
id val = [argStack objectAtIndex:offs+1];
2022-08-05 05:28:41 -04:00
NSMapTable *layer =
2022-08-05 05:28:40 -04:00
[[envStack lastObject] lookup:sym];
2022-08-05 05:28:41 -04:00
if(layer==NULL){
2022-08-05 05:28:40 -04:00
NSString *format =
@"symbol %@ not bound; can't assign to it";
errflag = YES;
errmsg =
[[NSString alloc]
initWithFormat:format
locale: nil, sym];
break;
}
2022-08-05 05:28:41 -04:00
id obj = [argStack objectAtIndex:(offs+1)]; [obj retain];
NSMapInsert(layer, [[argStack objectAtIndex:offs] symVal], obj);
2022-08-05 05:28:40 -04:00
[argStack removeObjectAtIndex:offs];
} break;
case IN_CLOSURE:{
int pos = [argStack count]-2;
id closure =
[Closure newArgs:[argStack objectAtIndex:pos]
Body:[argStack objectAtIndex:(pos+1)]
Env:[envStack lastObject]];
[argStack removeLastObject];
[argStack removeLastObject];
2022-08-05 05:28:41 -04:00
[argStack addObject:closure];
2022-08-05 05:28:40 -04:00
} break;
case IN_IF:{
BOOL isfalse = isFalse([argStack lastObject]);
2022-08-05 05:28:41 -04:00
[self pushByteCodes:(isfalse==YES ?
[instr arg2] : [instr arg1])];
2022-08-05 05:28:40 -04:00
[argStack removeLastObject];
} break;
case IN_LAYER:{
int count = [instr intarg1];
int offs = [argStack count]-2;
2022-08-05 05:28:41 -04:00
NSMapTable *layer =
NSCreateMapTable(NSObjectMapKeyCallBacks,
NSNonRetainedObjectMapValueCallBacks, 1);
2022-08-05 05:28:40 -04:00
id env;
while(count--){
2022-08-05 05:28:41 -04:00
id obj = [argStack objectAtIndex:(offs+1)]; [obj retain];
NSMapInsert(layer, [[argStack objectAtIndex:offs] symVal], obj);
2022-08-05 05:28:40 -04:00
[argStack removeLastObject];
[argStack removeLastObject];
offs-=2;
}
env = [Environment
newParent:[envStack lastObject] Data:layer];
2022-08-05 05:28:41 -04:00
[envStack addObject:env];
2022-08-05 05:28:40 -04:00
} break;
case IN_MEMQ:{
id list = [argStack lastObject];
id search;
[argStack removeLastObject];
search = [argStack lastObject];
while(isPair(list)){
if(isEqual(search, [list car])==YES){
break;
}
list = [list cdr];
}
2022-08-05 05:28:41 -04:00
[argStack addObject:list];
2022-08-05 05:28:40 -04:00
} break;
case IN_DUP_ARG: {
if([argStack count]<1){
errflag = YES;
errmsg = @"missing item (duplicate)";
}
else{
2022-08-05 05:28:41 -04:00
[argStack addObject:[argStack lastObject]];
2022-08-05 05:28:40 -04:00
}
} break;
case IN_EXCH_ARGS: {
if([argStack count]<2){
errflag = YES;
errmsg = @"missing items (exchange)";
}
else{
id item1, item2;
item1 = [argStack lastObject];
[argStack removeLastObject];
item2 = [argStack lastObject];
[argStack removeLastObject];
2022-08-05 05:28:41 -04:00
[argStack addObject:item1];
[argStack addObject:item2];
2022-08-05 05:28:40 -04:00
}
} break;
case IN_STATE_TO_THUNK:{
Thunk *t = [instr arg1];
[t setArgp:[argStack count]];
[t setEnvp:[envStack count]];
[t setCodep:[codeStack count]];
} break;
case IN_MARK_THUNK:{
Thunk *t = [instr arg1];
[t setArgp:-1];
[t setEnvp:-1];
[t setCodep:-1];
} break;
default:
errflag = YES;
errmsg =
[[NSString alloc]
initWithFormat:@"instruction unknown (tag %d)"
locale: nil, [instr tag]];
}
if([codeStack count]>maxcode){
maxcode = [codeStack count];
}
if([pcStack count]>maxpc){
maxpc = [pcStack count];
}
if([argStack count]>maxarg){
maxarg = [argStack count];
}
if([envStack count]>maxenv){
maxenv = [envStack count];
}
if(errflag==YES){
break;
}
if([SCMType totalAllocated]>4*[SCMType allocatedAfterGC]){
int ptotal = [SCMType totalAllocated];
NSString *msg,
2022-08-05 05:28:41 -04:00
*format = @"\n%@\nGC prev: %d now: %d\n",
2022-08-05 05:28:40 -04:00
*cformat = @"%@ prev: %d now: %d\n";
struct {
Class cl;
int prev;
} *cent, classes[] = {
{ [Pair class], 0 },
{ [Environment class], 0 },
2022-08-05 05:28:41 -04:00
{ [Int class], 0 },
2022-08-05 05:28:40 -04:00
{ [Closure class], 0 },
{ [Vector class], 0 },
{ [Triple class], 0 },
{ [ByteCodes class], 0 },
2022-08-05 05:28:41 -04:00
{ [interruptDate class], 0 },
{ [NSTableView class], 0 },
{ [NSTableColumn class], 0 },
2022-08-05 05:28:40 -04:00
{ [NSScrollView class], 0 },
2022-08-05 05:28:41 -04:00
{ [SCMTextView class], 0 },
2022-08-05 05:28:40 -04:00
{ [NSWindow class], 0 },
{ nil, 0 }
};
for(cent=classes; cent->cl!=nil; cent++){
cent->prev = GSDebugAllocationCount(cent->cl);
}
[SCMType nextMark];
[SCMType currentMarkForMarkables];
// [source setMarkToCurrent];
2022-08-05 05:28:41 -04:00
int codeind, codemx = [codeStack count];
for(codeind=0; codeind<codemx; codeind++){
id obj = [codeStack objectAtIndex:codeind];
if([obj root]==YES){
[obj setMarkToCurrent];
}
}
// [prog setMarkToCurrent];
2022-08-05 05:28:40 -04:00
2022-08-05 05:28:41 -04:00
int argind, argmx = [argStack count];
2022-08-05 05:28:40 -04:00
for(argind=0; argind<argmx; argind++){
id obj = [argStack objectAtIndex:argind];
if(MARKABLE(obj)){
[obj setMarkToCurrent];
}
}
[envStack makeObjectsPerformSelector:
@selector(setMarkToCurrent)];
[SCMType runGC];
[pool release];
pool = [NSAutoreleasePool new];
2022-08-05 05:28:41 -04:00
2022-08-05 05:28:40 -04:00
if(delegate!=nil &&
[delegate respondsToSelector:@selector(statistics:)]){
msg = [NSString stringWithFormat:format,
2022-08-05 05:28:41 -04:00
[[NSDate date] description],
2022-08-05 05:28:40 -04:00
ptotal, [SCMType totalAllocated]];
[delegate statistics:msg];
for(cent=classes; cent->cl!=nil; cent++){
msg = [NSString stringWithFormat:cformat,
NSStringFromClass(cent->cl),
cent->prev,
GSDebugAllocationCount(cent->cl)];
[delegate statistics:msg];
}
[delegate statistics:@"\n"];
}
}
}
2022-08-05 05:28:41 -04:00
if(inModal==YES){
[app endModalSession:interruptSession];
[interruptPanel close];
[NSCursor pop];
}
[interruptDate release];
2022-08-05 05:28:40 -04:00
[pool release];
2022-08-05 05:28:41 -04:00
/* getrusage(RUSAGE_SELF, &usg);
long end = usg.ru_utime.tv_sec;
NSLog(@"%u", end-start); */
2022-08-05 05:28:40 -04:00
return (errflag==YES ? NO : YES);
}
- special:(id)data output:(ByteCodes *)codes popenv:(int)ec
{
int tag = [data tag];
switch(tag){
case FORM_DEFINE1:
[codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:[data arg1]]];
[self compile:[data arg2] output:codes popenv:ec];
[codes addTriple:[Triple newTag:IN_DEFINE]];
break;
case FORM_DEFINE2: {
ByteCodes *body = [ByteCodes new];
[codes addTriple:[Triple newTag:IN_TO_ARGS
Arg1:[[data arg1] car]]];
[codes addTriple:[Triple newTag:IN_TO_ARGS
Arg1:[[data arg1] cdr]]];
[self sequence:[data arg2] output:body popenv:1];
[codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:body]];
[codes addTriple:[Triple newTag:IN_CLOSURE]];
if(ec>0){
[codes addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]];
}
[codes addTriple:[Triple newTag:IN_DEFINE]];
} break;
case FORM_SET:
[codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:[data arg1]]];
// [self compile:[data arg2] output:codes popenv:ec];
[self compile:[data arg2] output:codes popenv:0];
[codes addTriple:[Triple newTag:IN_SET]];
[codes addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]];
break;
case FORM_LAMBDA1:
case FORM_LAMBDA2: {
ByteCodes *body = [ByteCodes new];
[codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:[data arg1]]];
[self sequence:[data arg2] output:body popenv:1];
[codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:body]];
[codes addTriple:[Triple newTag:IN_CLOSURE]];
if(ec>0){
[codes addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]];
}
} break;
case FORM_BEGIN:
[self sequence:[data arg1] output:codes popenv:ec];
break;
case FORM_APPLY:
[self compile:[data arg1] output:codes popenv:0];
[codes addTriple:[Triple newTag:IN_CHECK_PTC]];
[self compile:[data arg2] output:codes popenv:ec];
[codes addTriple:[Triple newTag:IN_LIST_APPLIC]];
break;
case FORM_QUOTE:
if(ec>0){
[codes addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]];
}
[codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:[data arg1]]];
break;
case FORM_CALLCC:{
Thunk *t = [Thunk newArgp:-1 Envp:-1 Codep:-1];
[codes addTriple:[Triple newTag:IN_STATE_TO_THUNK Arg1:t]];
[self compile:[data arg1] output:codes popenv:ec];
[codes addTriple:[Triple newTag:IN_CHECK_PTC]];
[codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:t]];
[codes addTriple:[Triple newTag:IN_APPLIC IntArg1:1]];
[codes addTriple:[Triple newTag:IN_MARK_THUNK Arg1:t]];
} break;
case FORM_LET:
case FORM_LETSTAR:
case FORM_LETREC:{
int count = 0;
id bindings = [data arg1];
if(tag==FORM_LETREC){
[codes addTriple:[Triple newTag:IN_LAYER IntArg1:0]];
}
while(isPair(bindings)){
id binding = [bindings car];
[codes addTriple:[Triple newTag:IN_TO_ARGS
Arg1:[binding arg1]]];
[self compile:[binding arg2] output:codes popenv:0];
if(tag==FORM_LETREC){
[codes addTriple:[Triple newTag:IN_DEFINE]];
[codes addTriple:[Triple newTag:IN_POP_ARGS IntArg1:1]];
}
else if(tag==FORM_LETSTAR){
[codes addTriple:[Triple newTag:IN_LAYER IntArg1:1]];
}
count++; bindings = [bindings cdr];
}
if(tag==FORM_LET){
[codes addTriple:[Triple newTag:IN_LAYER IntArg1:count]];
}
[self sequence:[data arg2] output:codes
popenv:ec+(tag==FORM_LETSTAR? count : 1)];
} break;
case FORM_IF1:
case FORM_IF2: {
ByteCodes
*trueClause = [ByteCodes new],
*falseClause = [ByteCodes new];
[self compile:[data arg1] output:codes popenv:0];
[self compile:[data arg2] output:trueClause popenv:ec];
if([data arg3]!=nil){
[self compile:[data arg3] output:falseClause
popenv:ec];
}
else{
if(ec>0){
[falseClause
addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]];
}
[falseClause
addTriple:[Triple newTag:IN_TO_ARGS
Arg1:[NSNull null]]];
}
// [trueClause retain]; [falseClause retain];
[codes addTriple:[Triple newTag:IN_IF
Arg1:trueClause Arg2:falseClause]];
} break;
case FORM_COND: {
ByteCodes
*current, *endClause = [ByteCodes new];
id args, curcond;
args = [data arg1];
curcond = [args car];
if(isPair(curcond)){
[self sequence:[curcond cdr] output:endClause popenv:ec];
args = [args cdr];
}
else{
if(ec>0){
[endClause
addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]];
}
[endClause
addTriple:[Triple newTag:IN_TO_ARGS
Arg1:[NSNull null]]];
}
current = endClause; // [current retain];
while(isPair(args)){
ByteCodes
*clause = [ByteCodes new],
*match = [ByteCodes new];
int tag;
curcond = [args car]; tag = [curcond tag];
[self compile:[curcond arg1] output:clause popenv:0];
if(tag==FORM_SCOND1){
[clause addTriple:[Triple newTag:IN_DUP_ARG]];
[match addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]];
}
else if(tag==FORM_SCOND2){
[self sequence:[curcond arg2] output:match popenv:ec];
}
else{
[clause addTriple:[Triple newTag:IN_DUP_ARG]];
[self compile:[curcond arg2] output:match popenv:ec];
[match addTriple:[Triple newTag:IN_CHECK_PTC]];
[match addTriple:[Triple newTag:IN_EXCH_ARGS]];
[match addTriple:[Triple newTag:IN_APPLIC IntArg1:1]];
[current prependTriple:
[Triple newTag:IN_POP_ARGS IntArg1:1]];
}
[clause addTriple:
[Triple newTag:IN_IF
Arg1:match Arg2:current]];
current = clause; // [current retain];
args = [args cdr];
}
[codes appendByteCodes:current];
} break;
case FORM_CASE: {
ByteCodes
*endClause = [ByteCodes new];
id current, args, curcase;
args = [data arg2];
curcase = [args car];
[endClause addTriple:[Triple newTag:IN_POP_ARGS IntArg1:1]];
if([curcase car]==[NSNull null]){
[self sequence:[curcase cdr] output:endClause popenv:ec];
args = [args cdr];
}
else{
if(ec>0){
[endClause
addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]];
}
[endClause
addTriple:[Triple newTag:IN_TO_ARGS
Arg1:[NSNull null]]];
}
[self compile:[data arg1] output:codes popenv:0];
current = endClause;
while(isPair(args)){
ByteCodes
*clause = [ByteCodes new],
*match = [ByteCodes new];
curcase = [args car];
[clause
addTriple:[Triple newTag:IN_TO_ARGS
Arg1:[curcase car]]];
[clause addTriple:[Triple newTag:IN_MEMQ]];
[match addTriple:[Triple newTag:IN_POP_ARGS IntArg1:1]];
[self sequence:[curcase cdr] output:match popenv:ec];
[clause addTriple:
[Triple newTag:IN_IF
Arg1:match Arg2:current]];
current = clause; // [current retain];
args = [args cdr];
}
[codes appendByteCodes:current];
} break;
case FORM_AND:
case FORM_OR: {
ByteCodes
*trueClause = [ByteCodes new],
*falseClause = [ByteCodes new],
*current;
id args;
if(ec>0){
[trueClause
addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]];
}
[trueClause
addTriple:[Triple newTag:IN_TO_ARGS
Arg1:[[Boolean alloc] initSCMBoolean:YES]]];
if(ec>0){
[falseClause
addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]];
}
[falseClause
addTriple:[Triple newTag:IN_TO_ARGS
Arg1:[[Boolean alloc] initSCMBoolean:NO]]];
2022-08-05 05:28:41 -04:00
2022-08-05 05:28:40 -04:00
current = (tag == FORM_AND ? trueClause : falseClause);
args = [data arg1];
while(isPair(args)){
ByteCodes
*clause = [ByteCodes new];
[self compile:[args car] output:clause popenv:0];
if(tag == FORM_AND){
[clause addTriple:
[Triple newTag:IN_IF
Arg1:current Arg2:falseClause]];
}
else{
[clause addTriple:
[Triple newTag:IN_IF
Arg1:trueClause Arg2:current]];
}
current = clause; // [current retain];
args = [args cdr];
}
[codes appendByteCodes:current];
} break;
default:
errflag = YES;
errmsg =
[[NSString alloc]
initWithFormat:@"scheme form unknown (tag %d)"
locale: nil, [data tag]];
}
}
- sequence:(id)data output:(ByteCodes *)codes popenv:(int)ec
{
while(isPair(data)){
BOOL beforeLast = isPair([data cdr]);
[self compile:[data car] output:codes
popenv:(beforeLast==YES ? 0 : ec)];
if(beforeLast==YES){
[codes addTriple:[Triple newTag:IN_POP_ARGS IntArg1:1]];
}
data = [data cdr];
}
}
- compile:(id)data output:(ByteCodes *)codes popenv:(int)ec
{
BOOL application = NO;
int count = 0;
if(isTriple(data)){
return [self special:data output:codes popenv:ec];
}
else if(isPair(data)){
application = YES;
while(isPair(data)){
[self compile:[data car] output:codes popenv:0];
count++;
if(count==1){
[codes addTriple:[Triple newTag:IN_CHECK_PTC]];
}
data = [data cdr];
}
}
else if(isSymbol(data)){
[codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:data]];
[codes addTriple:[Triple newTag:IN_LOOKUP]];
}
else{
[codes addTriple:[Triple newTag:IN_TO_ARGS Arg1:data]];
}
if(ec>0){
[codes addTriple:[Triple newTag:IN_POP_ENV IntArg1:ec]];
}
if(application){
[codes addTriple:[Triple newTag:IN_APPLIC IntArg1:(count-1)]];
}
}
- (BOOL)compile:(id)data output:(ByteCodes *)codes
{
errflag = NO;
errmsg = @"";
[self compile:data output:codes popenv:0];
return errflag;
}
void yyrestart(FILE *);
extern char *yyinputstr, *yyinputstart;
extern int yysofar;
extern int yyinputline;
extern int yyinputitem;
2022-08-05 05:28:41 -04:00
- parse:(NSString *)scmText
2022-08-05 05:28:40 -04:00
{
yyinputline = 0;
yyinputitem = 0;
yyschemeerrflag = NO;
2022-08-05 05:28:41 -04:00
if(positionStack==nil){
positionStack = [NSMutableArray arrayWithCapacity:1];
[positionStack retain];
}
[positionStack addObject:[NSMutableArray arrayWithCapacity:1]];
2022-08-05 05:28:40 -04:00
yyinputstr = yyinputstart =
2022-08-05 05:28:41 -04:00
(char *)[[scmText stringByAppendingString:@"\n"] cString];
2022-08-05 05:28:40 -04:00
yysofar = 0;
yyrestart(NULL);
yyparse();
2022-08-05 05:28:41 -04:00
return self;
}
#define STATS @"code: %d %d (%d) args: %d (%d) envs: %d (%d)\n"
#define PARSE_ERROR @"Parse error at item %d, line %d%@.\n"
- (BOOL)processString:(NSString *)data mode:(PROCESS_MODE)pmode
{
[self parse:data];
id forms;
int curitem = 0, curpos = 0, nextpos = 0;
errpos = -1;
2022-08-05 05:28:40 -04:00
if(yyschemeerrflag==YES){
2022-08-05 05:28:41 -04:00
errmsg = [[NSString alloc] initWithFormat:PARSE_ERROR,
yyinputitem+1, yyinputline+1,
(yysofar==[data length]+1 ? @" (at end)" : @"")];
2022-08-05 05:28:40 -04:00
errflag = YES;
2022-08-05 05:28:41 -04:00
errpos = yysofar-1;
2022-08-05 05:28:40 -04:00
if(delegate!=nil && pmode!=MODE_LOAD &&
[delegate respondsToSelector:@selector(result:)]){
[delegate result:[NSNull null]];
}
return NO;
}
2022-08-05 05:28:41 -04:00
[SCMType addToMarkables:yyresultform];
2022-08-05 05:28:40 -04:00
2022-08-05 05:28:41 -04:00
forms = yyresultform;
2022-08-05 05:28:40 -04:00
if(forms==[NSNull null]){
[delegate result:[NSNull null]];
}
2022-08-05 05:28:41 -04:00
char *yyips = yyinputstart;
id yyrf = yyresultform;
2022-08-05 05:28:40 -04:00
while(forms!=[NSNull null]){
2022-08-05 05:28:41 -04:00
yyinputstart = yyips;
2022-08-05 05:28:40 -04:00
ByteCodes *codes = [ByteCodes new];
BOOL err = [self compile:[forms arg1] output:codes];
2022-08-05 05:28:41 -04:00
// [VScheme printCodes:codes];
2022-08-05 05:28:40 -04:00
NSRange range;
int lower, upper;
char *first, *fp; int flen;
2022-08-05 05:28:41 -04:00
2022-08-05 05:28:40 -04:00
#define MAXLINE 41
#define CENTER " ... "
#define HALF ((MAXLINE-5)/2)
char second[MAXLINE+1];
2022-08-05 05:28:41 -04:00
range = [[[positionStack lastObject] objectAtIndex:curitem] rangeValue];
2022-08-05 05:28:40 -04:00
nextpos = range.location;
2022-08-05 05:28:41 -04:00
lower = curpos;
while(isspace(yyinputstart[lower])){
lower++;
}
upper = nextpos;
while(isspace(yyinputstart[upper])){
upper--;
}
2022-08-05 05:28:40 -04:00
2022-08-05 05:28:41 -04:00
first = fp = malloc(upper-lower+2);
2022-08-05 05:28:40 -04:00
while(lower<=upper){
if(isspace(yyinputstart[lower])){
BOOL foundRet = NO; int len=0;
while(isspace(yyinputstart[lower]) &&
lower<=upper){
if(yyinputstart[lower]=='\n'){
foundRet = YES;
}
lower++; len++;
}
if(foundRet==YES){
*fp++ = ' ';
}
else{
strncpy(fp, yyinputstart+lower-len, len);
fp += len;
}
}
else{
*fp++ = yyinputstart[lower];
lower++;
}
}
*fp = 0;
if((flen=strlen(first))<=MAXLINE){
strcpy(second, first);
}
else{
strncpy(second, first, HALF);
strcpy(second+HALF, CENTER);
strcpy(second+HALF+5, first+flen-HALF);
}
curitem++; curpos = nextpos;
if(err==NO){
[self clearOutput];
[self clearImage];
2022-08-05 05:28:41 -04:00
if(pmode==MODE_EVALUATE){
[delegate
input:[NSString stringWithCString:second]];
}
BOOL runResult = [self run:codes mode:pmode];
if(pmode!=MODE_LOAD){
if([output length]>0){
if(hadOutput==NO){
[delegate output:@"\n"];
}
[delegate output:output];
}
if(atImgStart==NO){
[self produceImage];
}
}
if(runResult==YES){
NSString *msg;
2022-08-05 05:28:40 -04:00
if(pmode!=MODE_LOAD){
[delegate result:[argStack lastObject]];
}
if(delegate!=nil &&
[delegate respondsToSelector:@selector(statistics:)]){
msg = [NSString stringWithFormat:STATS,
[codeStack count], maxpc, maxcode,
[argStack count], maxarg,
[envStack count], maxenv];
[delegate statistics:msg];
}
}
2022-08-05 05:28:41 -04:00
[self resetStacks];
[envStack
removeObjectsInRange:
NSMakeRange(1, [envStack count]-1)];
2022-08-05 05:28:40 -04:00
}
free(first);
forms = [forms arg2];
if(errflag==YES){
break;
}
}
2022-08-05 05:28:41 -04:00
[positionStack removeLastObject];
[SCMType removeFromMarkables:yyrf];
2022-08-05 05:28:40 -04:00
if(errflag==YES){
[delegate result:[NSNull null]];
[delegate statistics:errmsg];
[delegate statistics:@"\n"];
}
// [positions release];
return (errflag == YES ? NO : YES);
}
@end
@implementation SCMImageView
- (id)initWithFrame:(NSRect)frameRect
{
image = nil;
return [super initWithFrame:frameRect];
}
- (NSImage *)image
{
return image;
}
- setImage:(NSImage *)anImage
{
if(image!=nil){
[image release];
}
image = anImage;
if(image!=nil){
[image retain];
}
[self setNeedsDisplay:YES];
2022-08-05 05:28:41 -04:00
return self;
2022-08-05 05:28:40 -04:00
}
- (void)drawRect:(NSRect)aRect
{
if(image!=nil){
[image compositeToPoint:aRect.origin
fromRect:aRect
operation:NSCompositeCopy];
}
}
@end