2498 lines
48 KiB
Objective-C
2498 lines
48 KiB
Objective-C
|
|
#import "Primitive.h"
|
|
#import "VScheme.h"
|
|
#import "SchemeDelegate.h"
|
|
|
|
inline BOOL isBoolean(id item)
|
|
{
|
|
return [item isKindOfClass:[Boolean class]];
|
|
}
|
|
|
|
inline BOOL isChar(id item)
|
|
{
|
|
return [item isKindOfClass:[Char class]];
|
|
}
|
|
|
|
inline BOOL isInt(id item)
|
|
{
|
|
return [item isKindOfClass:[Int class]];
|
|
}
|
|
|
|
inline BOOL isDouble(id item)
|
|
{
|
|
return [item isKindOfClass:[Double class]];
|
|
}
|
|
|
|
inline BOOL isSymbol(id item)
|
|
{
|
|
return [item isKindOfClass:[Symbol class]];
|
|
}
|
|
|
|
inline BOOL isString(id item)
|
|
{
|
|
return [item isKindOfClass:[String class]];
|
|
}
|
|
|
|
inline BOOL isPair(id item)
|
|
{
|
|
return [item isKindOfClass:[Pair class]];
|
|
}
|
|
|
|
inline BOOL isVector(id item)
|
|
{
|
|
return [item isKindOfClass:[Vector class]];
|
|
}
|
|
|
|
inline BOOL isTriple(id item)
|
|
{
|
|
return [item isKindOfClass:[Triple class]];
|
|
}
|
|
|
|
inline BOOL isPrimitive(id item)
|
|
{
|
|
return [item isKindOfClass:[Primitive class]];
|
|
}
|
|
|
|
inline BOOL isEval(id item)
|
|
{
|
|
return [item isKindOfClass:[PRMEval class]];
|
|
}
|
|
|
|
inline BOOL isClosure(id item)
|
|
{
|
|
return [item isKindOfClass:[Closure class]];
|
|
}
|
|
|
|
inline BOOL isThunk(id item)
|
|
{
|
|
return [item isKindOfClass:[Thunk class]];
|
|
}
|
|
|
|
BOOL isFalse(id item)
|
|
{
|
|
if(item==[NSNull null]){
|
|
return YES;
|
|
}
|
|
|
|
if([item isKindOfClass:[Boolean class]]){
|
|
return ([item boolVal]==YES ? NO : YES);
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
BOOL isEqual(id itema, id itemb)
|
|
{
|
|
if([itema class]!=[itemb class]){
|
|
return NO;
|
|
}
|
|
|
|
if(isChar(itema)){
|
|
return ([itema charVal]==[itemb charVal] ? YES : NO);
|
|
}
|
|
else if(isInt(itema)){
|
|
return ([itema intVal]==[itemb intVal] ? YES : NO);
|
|
}
|
|
else if(isDouble(itema)){
|
|
return ([itema doubleVal]==[itemb doubleVal] ? YES : NO);
|
|
}
|
|
else if(isBoolean(itema)){
|
|
return ([itema boolVal]==[itemb boolVal] ? YES : NO);
|
|
}
|
|
else if(isString(itema)){
|
|
return [[itema strVal] isEqual:[itemb strVal]];
|
|
}
|
|
else if(isSymbol(itema)){
|
|
return [[itema symVal] isEqual:[itemb symVal]];
|
|
}
|
|
|
|
return (itema==itemb ? YES : NO);
|
|
}
|
|
|
|
|
|
@implementation Primitive
|
|
|
|
- init
|
|
{
|
|
[super init];
|
|
|
|
value = [NSNull null];
|
|
errmsg = nil;
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
- (NUMTYPE)checkArgsNumeric:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
int pos;
|
|
NUMTYPE res = NT_INTEGERS;
|
|
|
|
for(pos=offs; pos<[args count]; pos++){
|
|
id arg = [args objectAtIndex:pos];
|
|
if(isInt(arg)==NO){
|
|
if(isDouble(arg)==NO){
|
|
return NT_OTHER;
|
|
}
|
|
res = NT_DOUBLE;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
[self notImplemented: _cmd];
|
|
return NO;
|
|
}
|
|
|
|
- (NSString *)primName
|
|
{
|
|
[self notImplemented: _cmd];
|
|
return @"_not_implemented";
|
|
}
|
|
|
|
- value
|
|
{
|
|
return value;
|
|
}
|
|
|
|
- errmsg
|
|
{
|
|
if([errmsg isKindOfClass:[NSConstantString class]]==NO){
|
|
[errmsg autorelease];
|
|
}
|
|
return errmsg;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMVectorPred
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"vector?";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id item;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"vector? takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs];
|
|
|
|
value = [[Boolean alloc] initSCMBoolean:isVector(item)];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMPairPred
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"pair?";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id item;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"pair? takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs];
|
|
|
|
value = [[Boolean alloc] initSCMBoolean:isPair(item)];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMNullPred
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"null?";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id item;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"null? takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs];
|
|
|
|
value = [[Boolean alloc]
|
|
initSCMBoolean:(item==[NSNull null] ? YES : NO)];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMZeroPred
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"zero?";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
id item;
|
|
BOOL res = NO;
|
|
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"zero? takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs];
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to zero? must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_INTEGERS){
|
|
if(![item intVal]){
|
|
res = YES;
|
|
}
|
|
}
|
|
else{
|
|
if([item doubleVal]==(double)0.0){
|
|
res = YES;
|
|
}
|
|
}
|
|
|
|
value = [[Boolean alloc] initSCMBoolean:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMNumberPred
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"number?";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
id item;
|
|
BOOL res = NO;
|
|
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"number? takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs];
|
|
|
|
res = (nt!=NT_OTHER ? YES : NO);
|
|
|
|
value = [[Boolean alloc] initSCMBoolean:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMEqPred
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"eq?";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id itema, itemb;
|
|
BOOL res = NO;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"eq? takes two arguments";
|
|
return NO;
|
|
}
|
|
|
|
itema = [args objectAtIndex:offs];
|
|
itemb = [args objectAtIndex:offs+1];
|
|
|
|
value = [[Boolean alloc] initSCMBoolean:isEqual(itema, itemb)];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMNot
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"not";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id item;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"not takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs];
|
|
|
|
value = [[Boolean alloc] initSCMBoolean:isFalse(item)];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMNumEqual
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"=";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
int icur, ires = 0; double dcur, dres = 0;
|
|
int pos = offs;
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
BOOL res = YES;
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Arguments to = must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_INTEGERS){
|
|
ires = [[args objectAtIndex:offs] intVal];
|
|
for(pos=offs+1; pos<[args count]; pos++){
|
|
icur = [[args objectAtIndex:pos] intVal];
|
|
if(!(ires==icur)){
|
|
res = NO;
|
|
break;
|
|
}
|
|
ires = icur;
|
|
}
|
|
}
|
|
else{
|
|
dres = [[args objectAtIndex:offs] doubleVal];
|
|
for(pos=offs+1; pos<[args count]; pos++){
|
|
dcur = [[args objectAtIndex:pos] doubleVal];
|
|
if(!(dres==dcur)){
|
|
res = NO;
|
|
break;
|
|
}
|
|
dres = dcur;
|
|
}
|
|
}
|
|
|
|
value = [[Boolean alloc] initSCMBoolean:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMNumLT
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"<";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
int icur, ires = 0; double dcur, dres = 0;
|
|
int pos = offs;
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
BOOL res = YES;
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Arguments to < must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_INTEGERS){
|
|
ires = [[args objectAtIndex:offs] intVal];
|
|
for(pos=offs+1; pos<[args count]; pos++){
|
|
icur = [[args objectAtIndex:pos] intVal];
|
|
if(!(ires<icur)){
|
|
res = NO;
|
|
break;
|
|
}
|
|
ires = icur;
|
|
}
|
|
}
|
|
else{
|
|
dres = [[args objectAtIndex:offs] doubleVal];
|
|
for(pos=offs+1; pos<[args count]; pos++){
|
|
dcur = [[args objectAtIndex:pos] doubleVal];
|
|
if(!(dres<dcur)){
|
|
res = NO;
|
|
break;
|
|
}
|
|
dres = dcur;
|
|
}
|
|
}
|
|
|
|
value = [[Boolean alloc] initSCMBoolean:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMNumGT
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @">";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
int icur, ires = 0; double dcur, dres = 0;
|
|
int pos = offs;
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
BOOL res = YES;
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Arguments to > must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_INTEGERS){
|
|
ires = [[args objectAtIndex:offs] intVal];
|
|
for(pos=offs+1; pos<[args count]; pos++){
|
|
icur = [[args objectAtIndex:pos] intVal];
|
|
if(!(ires>icur)){
|
|
res = NO;
|
|
break;
|
|
}
|
|
ires = icur;
|
|
}
|
|
}
|
|
else{
|
|
dres = [[args objectAtIndex:offs] doubleVal];
|
|
for(pos=offs+1; pos<[args count]; pos++){
|
|
dcur = [[args objectAtIndex:pos] doubleVal];
|
|
if(!(dres>dcur)){
|
|
res = NO;
|
|
break;
|
|
}
|
|
dres = dcur;
|
|
}
|
|
}
|
|
|
|
value = [[Boolean alloc] initSCMBoolean:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMPlus
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"+";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
int ires = 0; double dres = 0;
|
|
int pos = offs;
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Arguments to + must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_INTEGERS){
|
|
for(pos=offs; pos<[args count]; pos++){
|
|
ires += [[args objectAtIndex:pos] intVal];
|
|
}
|
|
|
|
value = [[Int alloc] initSCMInt:ires];
|
|
return YES;
|
|
}
|
|
|
|
for(pos=offs; pos<[args count]; pos++){
|
|
dres += [[args objectAtIndex:pos] doubleVal];
|
|
}
|
|
|
|
value = [[Double alloc] initSCMDouble:dres];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMTimes
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"*";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
int ires = 1; double dres = 1;
|
|
int pos = offs;
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Arguments to * must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_INTEGERS){
|
|
for(pos=offs; pos<[args count]; pos++){
|
|
ires *= [[args objectAtIndex:pos] intVal];
|
|
}
|
|
|
|
value = [[Int alloc] initSCMInt:ires];
|
|
return YES;
|
|
}
|
|
|
|
for(pos=offs; pos<[args count]; pos++){
|
|
dres *= [[args objectAtIndex:pos] doubleVal];
|
|
}
|
|
|
|
value = [[Double alloc] initSCMDouble:dres];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMMinus
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"-";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
int ires = 1; double dres = 1;
|
|
int pos = offs;
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
|
|
if(offs==[args count]){
|
|
errmsg = @"- needs at least one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Arguments to - must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_INTEGERS){
|
|
ires = [[args objectAtIndex:offs] intVal];
|
|
if(offs+1==[args count]){
|
|
ires = -ires;
|
|
}
|
|
else{
|
|
for(pos=offs+1; pos<[args count]; pos++){
|
|
ires -= [[args objectAtIndex:pos] intVal];
|
|
}
|
|
}
|
|
value = [[Int alloc] initSCMInt:ires];
|
|
return YES;
|
|
}
|
|
|
|
dres = [[args objectAtIndex:offs] doubleVal];
|
|
if(offs+1==[args count]){
|
|
dres = -dres;
|
|
}
|
|
else{
|
|
for(pos=offs+1; pos<[args count]; pos++){
|
|
dres -= [[args objectAtIndex:pos] doubleVal];
|
|
}
|
|
}
|
|
value = [[Double alloc] initSCMDouble:dres];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMDivide
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"/";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
int ires = 1; double dres = 1;
|
|
int pos = offs;
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
|
|
if(offs==[args count]){
|
|
errmsg = @"/ needs at least one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Arguments to / must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_INTEGERS){
|
|
ires = [[args objectAtIndex:offs] intVal];
|
|
if(offs+1==[args count]){
|
|
if(ires!=1){
|
|
errmsg = @"no integer fractions";
|
|
return NO;
|
|
}
|
|
}
|
|
else{
|
|
for(pos=offs+1; pos<[args count]; pos++){
|
|
ires /= [[args objectAtIndex:pos] intVal];
|
|
}
|
|
}
|
|
value = [[Int alloc] initSCMInt:ires];
|
|
return YES;
|
|
}
|
|
|
|
dres = [[args objectAtIndex:offs] doubleVal];
|
|
if(offs+1==[args count]){
|
|
dres = ((double)1.0)/dres;
|
|
}
|
|
else{
|
|
for(pos=offs+1; pos<[args count]; pos++){
|
|
dres /= [[args objectAtIndex:pos] doubleVal];
|
|
}
|
|
}
|
|
value = [[Double alloc] initSCMDouble:dres];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMRandom
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"random";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"random takes exactly one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"argument to random must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_INTEGERS){
|
|
int v = [[args objectAtIndex:offs] intVal];
|
|
value = [[Int alloc] initSCMInt:(lrand48() % v)];
|
|
}
|
|
else{
|
|
double v = [[args objectAtIndex:offs] doubleVal];
|
|
value = [[Double alloc] initSCMDouble:(drand48() * v)];
|
|
}
|
|
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMQuotient
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"quotient";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
int a, b;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"quotient takes exactly two arguments";
|
|
return NO;
|
|
}
|
|
|
|
if(nt!=NT_INTEGERS){
|
|
errmsg = @"Arguments to quotient must be integers";
|
|
return NO;
|
|
}
|
|
|
|
a = [[args objectAtIndex:offs] intVal];
|
|
b = [[args objectAtIndex:offs+1] intVal];
|
|
|
|
if(!b){
|
|
errmsg = @"divide by zero error in quotient";
|
|
return NO;
|
|
}
|
|
|
|
value = [[Int alloc] initSCMInt:(a/b)];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMRemainder
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"remainder";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
int a, b;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"remainder takes exactly two arguments";
|
|
return NO;
|
|
}
|
|
|
|
if(nt!=NT_INTEGERS){
|
|
errmsg = @"Arguments to remainder must be integers";
|
|
return NO;
|
|
}
|
|
|
|
a = [[args objectAtIndex:offs] intVal];
|
|
b = [[args objectAtIndex:offs+1] intVal];
|
|
|
|
if(!b){
|
|
errmsg = @"divide by zero error in remainder";
|
|
return NO;
|
|
}
|
|
|
|
value = [[Int alloc] initSCMInt:(a%b)];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMList
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"list";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id res = [NSNull null];
|
|
int pos;
|
|
|
|
for(pos=[args count]-1; pos>=offs; pos--){
|
|
res = [Pair newCar:[args objectAtIndex:pos] Cdr:res];
|
|
}
|
|
|
|
value = res;
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMCons
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"cons";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"cons takes exactly two arguments";
|
|
return NO;
|
|
}
|
|
|
|
value = [Pair
|
|
newCar:[args objectAtIndex:offs]
|
|
Cdr:[args objectAtIndex:offs+1]];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMCar
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"car";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id item;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"car takes exactly one argument";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs];
|
|
if(isPair(item)==NO){
|
|
errmsg = @"argument to car must be a pair";
|
|
return NO;
|
|
}
|
|
|
|
value = [item car];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMCdr
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"cdr";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id item;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"cdr takes exactly one argument";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs];
|
|
if(isPair(item)==NO){
|
|
errmsg = @"argument to cdr must be a pair";
|
|
return NO;
|
|
}
|
|
|
|
value = [item cdr];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMSetCar
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"set-car!";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id item;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"set-car! takes two arguments";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs];
|
|
if(isPair(item)==NO){
|
|
errmsg = @"argument to set-car! must be a pair";
|
|
return NO;
|
|
}
|
|
|
|
[item setcar:[args objectAtIndex:(offs+1)]];
|
|
|
|
value = [item car];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMSetCdr
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"set-cdr!";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id item;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"set-cdr! takes two arguments";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs];
|
|
if(isPair(item)==NO){
|
|
errmsg = @"argument to set-cdr! must be a pair";
|
|
return NO;
|
|
}
|
|
|
|
[item setcdr:[args objectAtIndex:(offs+1)]];
|
|
|
|
value = [item cdr];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMDisplay
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"display";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id item;
|
|
NSString *res;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"display takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs];
|
|
|
|
if(isString(item)){
|
|
res = [NSString
|
|
stringWithFormat:@"%@", [item strVal]];
|
|
}
|
|
else if(isChar(item)){
|
|
res = [NSString
|
|
stringWithFormat:@"%c", [item charVal]];
|
|
}
|
|
else{
|
|
res = [VScheme valToString:item];
|
|
}
|
|
[vm appendToOutput:res];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMNewline
|
|
|
|
- (NSString *)primName
|
|
{
|
|
return @"newline";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id item;
|
|
|
|
if(offs!=[args count]){
|
|
errmsg = @"newline takes no arguments";
|
|
return NO;
|
|
}
|
|
|
|
[vm appendToOutput:@"\n"];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMDrawMove
|
|
- (NSString *)primName
|
|
{
|
|
return @"draw-move";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
DrawInst inst;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"draw-move takes two arguments";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Arguments to draw-move must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
inst.what = DRAW_MOVE;
|
|
inst.data.coord.x = [[args objectAtIndex:offs] doubleVal];
|
|
inst.data.coord.y = [[args objectAtIndex:offs+1] doubleVal];
|
|
|
|
[vm recordImgInst:inst];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMDrawLine
|
|
- (NSString *)primName
|
|
{
|
|
return @"draw-line";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
DrawInst inst;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"draw-line takes two arguments";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Arguments to draw-line must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
inst.what = DRAW_LINE;
|
|
inst.data.coord.x = [[args objectAtIndex:offs] doubleVal];
|
|
inst.data.coord.y = [[args objectAtIndex:offs+1] doubleVal];
|
|
|
|
[vm recordImgInst:inst];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMDrawColor
|
|
- (NSString *)primName
|
|
{
|
|
return @"draw-color";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
DrawInst inst;
|
|
|
|
if(offs+3!=[args count]){
|
|
errmsg = @"draw-color takes three arguments";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Arguments to draw-color must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
inst.what = DRAW_COLOR;
|
|
inst.data.color[0] = [[args objectAtIndex:offs] doubleVal];
|
|
inst.data.color[1] = [[args objectAtIndex:offs+1] doubleVal];
|
|
inst.data.color[2] = [[args objectAtIndex:offs+2] doubleVal];
|
|
|
|
if(inst.data.color[0]<(float)0 ||
|
|
inst.data.color[0]>(float)255){
|
|
errmsg = @"red color component out of range (0..255)";
|
|
return NO;
|
|
}
|
|
if(inst.data.color[1]<(float)0 ||
|
|
inst.data.color[1]>(float)255){
|
|
errmsg = @"green color component out of range (0..255)";
|
|
return NO;
|
|
}
|
|
if(inst.data.color[2]<(float)0 ||
|
|
inst.data.color[2]>(float)255){
|
|
errmsg = @"blue color component out of range (0..255)";
|
|
return NO;
|
|
}
|
|
|
|
inst.data.color[0]/=(float)255;
|
|
inst.data.color[1]/=(float)255;
|
|
inst.data.color[2]/=(float)255;
|
|
|
|
[vm recordImgInst:inst];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMDrawCircle
|
|
- (NSString *)primName
|
|
{
|
|
return @"draw-circle";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
DrawInst inst;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"draw-circle takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to draw-circle must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
inst.what = DRAW_CIRCLE;
|
|
inst.data.radius = [[args objectAtIndex:offs] doubleVal];
|
|
|
|
[vm recordImgInst:inst];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMFillCircle
|
|
- (NSString *)primName
|
|
{
|
|
return @"fill-circle";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
DrawInst inst;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"fill-circle takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to fill-circle must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
inst.what = FILL_CIRCLE;
|
|
inst.data.radius = [[args objectAtIndex:offs] doubleVal];
|
|
|
|
[vm recordImgInst:inst];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMDrawRect
|
|
- (NSString *)primName
|
|
{
|
|
return @"draw-rect";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
DrawInst inst;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"draw-rect takes two arguments";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Arguments to draw-rect must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
inst.what = DRAW_RECT;
|
|
inst.data.size =
|
|
NSMakeSize([[args objectAtIndex:offs] doubleVal],
|
|
[[args objectAtIndex:offs+1] doubleVal]);
|
|
|
|
[vm recordImgInst:inst];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMFillRect
|
|
- (NSString *)primName
|
|
{
|
|
return @"fill-rect";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
DrawInst inst;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"fill-rect takes two arguments";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to fill-rect must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
inst.what = FILL_RECT;
|
|
inst.data.size =
|
|
NSMakeSize([[args objectAtIndex:offs] doubleVal],
|
|
[[args objectAtIndex:offs+1] doubleVal]);
|
|
|
|
[vm recordImgInst:inst];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMDrawFont
|
|
- (NSString *)primName
|
|
{
|
|
return @"draw-font";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
DrawInst inst;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"draw-font takes two arguments";
|
|
return NO;
|
|
}
|
|
|
|
String *fontName = [args objectAtIndex:offs];
|
|
if(isString(fontName)==NO){
|
|
errmsg = @"draw-font: font name must be a string";
|
|
return NO;
|
|
}
|
|
|
|
NSString *fontNameStr = [fontName strVal];
|
|
if([[[NSFontManager sharedFontManager]
|
|
availableFonts] containsObject:fontNameStr]==NO){
|
|
errmsg =
|
|
[[NSString alloc]
|
|
initWithFormat:@"draw-font: no such font (%@)", fontNameStr];
|
|
return NO;
|
|
}
|
|
|
|
id size = [args objectAtIndex:offs+1];
|
|
if(isInt(size)==NO && isDouble(size)==NO){
|
|
errmsg = @"draw-font: size must be a number";
|
|
return NO;
|
|
}
|
|
|
|
float sizeVal = (float)[size doubleVal];
|
|
NSFont *font = [NSFont fontWithName:fontNameStr size:sizeVal];
|
|
[font retain];
|
|
|
|
inst.what = DRAW_FONT;
|
|
inst.data.font = font;
|
|
|
|
[vm recordImgInst:inst];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMDrawString
|
|
- (NSString *)primName
|
|
{
|
|
return @"draw-string";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
DrawInst inst;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"draw-string takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
String *str = [args objectAtIndex:offs];
|
|
if(isString(str)==NO){
|
|
errmsg = @"draw-string: string required";
|
|
return NO;
|
|
}
|
|
|
|
NSString *string = [NSString stringWithString:[str strVal]];
|
|
[string retain];
|
|
|
|
inst.what = DRAW_STRING;
|
|
inst.data.string = string;
|
|
|
|
[vm recordImgInst:inst];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
@implementation PRMDrawShow
|
|
- (NSString *)primName
|
|
{
|
|
return @"draw-show";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs!=[args count]){
|
|
errmsg = @"draw-show takes no argument";
|
|
return NO;
|
|
}
|
|
|
|
[vm produceImage];
|
|
[vm clearImage];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMSin
|
|
- (NSString *)primName
|
|
{
|
|
return @"sin";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
double res;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"sin takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to sin must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
res = sin([[args objectAtIndex:offs] doubleVal]);
|
|
value = [[Double alloc] initSCMDouble:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMCos
|
|
- (NSString *)primName
|
|
{
|
|
return @"cos";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
double res;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"cos takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to cos must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
res = cos([[args objectAtIndex:offs] doubleVal]);
|
|
value = [[Double alloc] initSCMDouble:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMTan
|
|
- (NSString *)primName
|
|
{
|
|
return @"tan";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
double res;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"tan takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to tan must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
res = tan([[args objectAtIndex:offs] doubleVal]);
|
|
value = [[Double alloc] initSCMDouble:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMExp
|
|
- (NSString *)primName
|
|
{
|
|
return @"exp";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
double res;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"exp takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to exp must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
res = exp([[args objectAtIndex:offs] doubleVal]);
|
|
value = [[Double alloc] initSCMDouble:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMLog
|
|
- (NSString *)primName
|
|
{
|
|
return @"log";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
double v, res;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"log takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to log must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
v = [[args objectAtIndex:offs] doubleVal];
|
|
if(v<=0.0){
|
|
errmsg = @"Argument to log must be positive";
|
|
return NO;
|
|
}
|
|
|
|
res = log(v);
|
|
value = [[Double alloc] initSCMDouble:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMATan
|
|
- (NSString *)primName
|
|
{
|
|
return @"atan";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
double res, v;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"atan takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to atan must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
v = [[args objectAtIndex:offs] doubleVal];
|
|
res = atan(v);
|
|
value = [[Double alloc] initSCMDouble:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMASin
|
|
- (NSString *)primName
|
|
{
|
|
return @"asin";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
double res, v;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"asin takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to asin must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
v = [[args objectAtIndex:offs] doubleVal];
|
|
if(v<(double)-1.0 || (double)1.0<v){
|
|
errmsg = @"Argument to asin out of range";
|
|
return NO;
|
|
}
|
|
|
|
res = asin(v);
|
|
value = [[Double alloc] initSCMDouble:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMACos
|
|
- (NSString *)primName
|
|
{
|
|
return @"acos";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
double res, v;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"acos takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to acos must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
v = [[args objectAtIndex:offs] doubleVal];
|
|
if(v<(double)-1.0 || (double)1.0<v){
|
|
errmsg = @"Argument to acos out of range";
|
|
return NO;
|
|
}
|
|
|
|
res = acos(v);
|
|
value = [[Double alloc] initSCMDouble:res];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMSqrt
|
|
- (NSString *)primName
|
|
{
|
|
return @"sqrt";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NUMTYPE nt = [self checkArgsNumeric:args offset:offs];
|
|
double v, res; int ires;
|
|
id item;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"sqrt takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
if(nt==NT_OTHER){
|
|
errmsg = @"Argument to sqrt must be numeric";
|
|
return NO;
|
|
}
|
|
|
|
item = [args objectAtIndex:offs]; v = [item doubleVal];
|
|
|
|
if(v<0){
|
|
errmsg = @"Argument to sqrt must not be negative";
|
|
return NO;
|
|
}
|
|
|
|
res = sqrt([item doubleVal]);
|
|
ires = (int)res;
|
|
|
|
if(nt==NT_INTEGERS && ires*ires==[item intVal]){
|
|
value = [[Int alloc] initSCMInt:ires];
|
|
}
|
|
else{
|
|
value = [[Double alloc] initSCMDouble:res];
|
|
}
|
|
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMMakeVector
|
|
- (NSString *)primName
|
|
{
|
|
return @"make-vector";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id filler;
|
|
id count;
|
|
int cval;
|
|
|
|
if(offs+1==[args count]){
|
|
filler = [NSNull null];
|
|
}
|
|
else if(offs+2==[args count]){
|
|
filler = [args objectAtIndex:offs+1];
|
|
}
|
|
else{
|
|
errmsg = @"make-vector takes one or two arguments";
|
|
return NO;
|
|
}
|
|
|
|
count = [args objectAtIndex:offs];
|
|
|
|
if(isInt(count)==NO){
|
|
errmsg = @"make-vector: integer required";
|
|
return NO;
|
|
}
|
|
|
|
cval = [count intVal];
|
|
|
|
if(cval<0){
|
|
errmsg = @"make-vector: non-negative integer required";
|
|
return NO;
|
|
}
|
|
|
|
value = [Vector newWithItem:filler count:cval];
|
|
|
|
return YES;
|
|
}
|
|
|
|
|
|
@end
|
|
|
|
@implementation PRMListToVector
|
|
- (NSString *)primName
|
|
{
|
|
return @"list->vector";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id list;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"list->vector takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
list = [args objectAtIndex:offs];
|
|
|
|
if(isPair(list)==NO && list!=[NSNull null]){
|
|
errmsg = @"list->vector: list required";
|
|
return NO;
|
|
}
|
|
|
|
value = [Vector newFromList:list];
|
|
|
|
return YES;
|
|
}
|
|
|
|
|
|
@end
|
|
|
|
@implementation PRMVectorToList
|
|
- (NSString *)primName
|
|
{
|
|
return @"vector->list";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
Vector *vect;
|
|
Pair *result;
|
|
id *data;
|
|
int index;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"vector->list takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
vect = [args objectAtIndex:offs];
|
|
|
|
if(isVector(vect)==NO){
|
|
errmsg = @"vector->list: vector required";
|
|
return NO;
|
|
}
|
|
|
|
data = [vect entries];
|
|
|
|
for(index=[vect count]-1, result=(Pair *)[NSNull null];
|
|
index>=0; index--){
|
|
result =
|
|
[Pair newCar:data[index] Cdr:result];
|
|
}
|
|
|
|
value = result;
|
|
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMVectorLength
|
|
- (NSString *)primName
|
|
{
|
|
return @"vector-length";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
Vector *vect;
|
|
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"vector-length takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
vect = [args objectAtIndex:offs];
|
|
|
|
if(isVector(vect)==NO){
|
|
errmsg = @"vector-length: vector required";
|
|
return NO;
|
|
}
|
|
|
|
value = [[Int alloc] initSCMInt:[vect count]];
|
|
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMVectorRef
|
|
- (NSString *)primName
|
|
{
|
|
return @"vector-ref";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id *data;
|
|
Vector *vect;
|
|
int count, index;
|
|
Int *ind;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"vector-ref takes two arguments";
|
|
return NO;
|
|
}
|
|
|
|
vect = [args objectAtIndex:offs];
|
|
if(isVector(vect)==NO){
|
|
errmsg = @"vector-ref: vector required";
|
|
return NO;
|
|
}
|
|
|
|
data = [vect entries]; count = [vect count];
|
|
|
|
ind = [args objectAtIndex:offs+1];
|
|
if(isInt(ind)==NO){
|
|
errmsg = @"vector-ref: integer required";
|
|
return NO;
|
|
}
|
|
|
|
index = [ind intVal];
|
|
if(index<0 || index>=count){
|
|
errmsg = @"vector-ref: index out of bounds";
|
|
return NO;
|
|
}
|
|
|
|
value = data[index];
|
|
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMVectorSet
|
|
- (NSString *)primName
|
|
{
|
|
return @"vector-set!";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id *data;
|
|
Vector *vect;
|
|
int count, index;
|
|
Int *ind;
|
|
id obj;
|
|
|
|
if(offs+3!=[args count]){
|
|
errmsg = @"vector-set! takes three arguments";
|
|
return NO;
|
|
}
|
|
|
|
vect = [args objectAtIndex:offs];
|
|
if(isVector(vect)==NO){
|
|
errmsg = @"vector-set!: vector required";
|
|
return NO;
|
|
}
|
|
|
|
data = [vect entries]; count = [vect count];
|
|
|
|
ind = [args objectAtIndex:offs+1];
|
|
if(isInt(ind)==NO){
|
|
errmsg = @"vector-set!: integer required";
|
|
return NO;
|
|
}
|
|
|
|
index = [ind intVal];
|
|
if(index<0 || index>=count){
|
|
errmsg = @"vector-set!: index out of bounds";
|
|
return NO;
|
|
}
|
|
|
|
obj = [args objectAtIndex:offs+2];
|
|
|
|
data[index] = obj; [obj retain];
|
|
|
|
value = obj;
|
|
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMVectorFill
|
|
- (NSString *)primName
|
|
{
|
|
return @"vector-fill!";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id *data;
|
|
Vector *vect;
|
|
int count, index;
|
|
id obj;
|
|
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"vector-fill! takes two arguments";
|
|
return NO;
|
|
}
|
|
|
|
vect = [args objectAtIndex:offs];
|
|
if(isVector(vect)==NO){
|
|
errmsg = @"vector-fill!: vector required";
|
|
return NO;
|
|
}
|
|
|
|
data = [vect entries]; count = [vect count];
|
|
|
|
obj = [args objectAtIndex:offs+1];
|
|
for(index=0; index<count; index++){
|
|
data[index] = obj; [obj retain];
|
|
}
|
|
|
|
value = obj;
|
|
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMSymToStr
|
|
- (NSString *)primName
|
|
{
|
|
return @"symbol->string";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"symbol->string takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
Symbol *sym = [args objectAtIndex:offs];
|
|
if(isSymbol(sym)==NO){
|
|
errmsg = @"symbol->string: symbol required";
|
|
return NO;
|
|
}
|
|
|
|
value = [[String alloc]
|
|
initSCMString:(char *)[[sym symVal] cString]];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
@implementation PRMStrToSym
|
|
- (NSString *)primName
|
|
{
|
|
return @"string->symbol";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"string->symbol takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
String *str = [args objectAtIndex:offs];
|
|
if(isString(str)==NO){
|
|
errmsg = @"string->symbol: string required";
|
|
return NO;
|
|
}
|
|
|
|
value = [[Symbol alloc]
|
|
initSCMSymbol:(char *)[[str strVal] cString]];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMStringSize
|
|
- (NSString *)primName
|
|
{
|
|
return @"string-size";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+3!=[args count]){
|
|
errmsg = @"string-size takes three arguments";
|
|
return NO;
|
|
}
|
|
|
|
String *str = [args objectAtIndex:offs];
|
|
if(isString(str)==NO){
|
|
errmsg = @"string-size: string required";
|
|
return NO;
|
|
}
|
|
|
|
String *fontName = [args objectAtIndex:offs+1];
|
|
if(isString(fontName)==NO){
|
|
errmsg = @"string-size: font name must be a string";
|
|
return NO;
|
|
}
|
|
|
|
NSString *fontNameStr = [fontName strVal];
|
|
if([[[NSFontManager sharedFontManager]
|
|
availableFonts] containsObject:fontNameStr]==NO){
|
|
errmsg =
|
|
[[NSString alloc]
|
|
initWithFormat:@"string-size: no such font (%@)", fontNameStr];
|
|
return NO;
|
|
}
|
|
|
|
id size = [args objectAtIndex:offs+2];
|
|
if(isInt(size)==NO && isDouble(size)==NO){
|
|
errmsg = @"string-size: size must be a number";
|
|
return NO;
|
|
}
|
|
|
|
float sizeVal = (float)[size doubleVal];
|
|
NSFont *font = [NSFont fontWithName:fontNameStr size:sizeVal];
|
|
|
|
NSDictionary *attr =
|
|
[NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
|
|
NSSize result = [[str strVal] sizeWithAttributes:attr];
|
|
|
|
value =
|
|
[Pair
|
|
newCar:[[Double alloc] initSCMDouble:result.width]
|
|
Cdr:[[Double alloc] initSCMDouble:result.height]];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMStringLength
|
|
- (NSString *)primName
|
|
{
|
|
return @"string-length";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"string-length takes three arguments";
|
|
return NO;
|
|
}
|
|
|
|
String *str = [args objectAtIndex:offs];
|
|
if(isString(str)==NO){
|
|
errmsg = @"string-length: string required";
|
|
return NO;
|
|
}
|
|
|
|
value = [[Int alloc] initSCMInt:[[str strVal] length]];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMCharToInt
|
|
- (NSString *)primName
|
|
{
|
|
return @"char->integer";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"char->integer takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
Char *ch = [args objectAtIndex:offs];
|
|
if(isChar(ch)==NO){
|
|
errmsg = @"char->integer: character required";
|
|
return NO;
|
|
}
|
|
|
|
value = [[Int alloc]
|
|
initSCMInt:(long int)[ch charVal]];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMIntToChar
|
|
- (NSString *)primName
|
|
{
|
|
return @"integer->char";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"integer->char takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
Int *i = [args objectAtIndex:offs];
|
|
if(isInt(i)==NO){
|
|
errmsg = @"integer->char: character required";
|
|
return NO;
|
|
}
|
|
|
|
value = [[Char alloc]
|
|
initSCMChar:(char)[i intVal]];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
@implementation PRMStringRef
|
|
- (NSString *)primName
|
|
{
|
|
return @"string-ref";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+2!=[args count]){
|
|
errmsg = @"string-ref takes two argument";
|
|
return NO;
|
|
}
|
|
|
|
String *str = [args objectAtIndex:offs];
|
|
if(isString(str)==NO){
|
|
errmsg = @"string-ref: string required";
|
|
return NO;
|
|
}
|
|
|
|
Int *i = [args objectAtIndex:offs+1];
|
|
if(isInt(i)==NO){
|
|
errmsg = @"string-ref: integer position required";
|
|
return NO;
|
|
}
|
|
int pos = [i intVal];
|
|
|
|
NSString *theStr = [str strVal];
|
|
if(pos>=[theStr length]){
|
|
errmsg = @"string-ref: index out of range";
|
|
return NO;
|
|
}
|
|
|
|
value = [[Char alloc] initSCMChar:[theStr characterAtIndex:pos]];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMListToStr
|
|
- (NSString *)primName
|
|
{
|
|
return @"list->string";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"list->string takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
Pair *p = [args objectAtIndex:offs];
|
|
if(isPair(p)==NO && [NSNull null]!=(id)p){
|
|
errmsg = @"list->string: pair required";
|
|
return NO;
|
|
}
|
|
|
|
int cpos = 0, cmax = 0;
|
|
while(isPair(p)){
|
|
if(isChar([p car])==NO){
|
|
errmsg = @"list->string: character required";
|
|
return NO;
|
|
}
|
|
p = [p cdr];
|
|
cmax++;
|
|
}
|
|
|
|
char buf[cmax+1];
|
|
p = [args objectAtIndex:offs];
|
|
|
|
while(isPair(p)){
|
|
Char *ch = [p car];
|
|
buf[cpos++] = [ch charVal];
|
|
|
|
p = [p cdr];
|
|
}
|
|
buf[cpos] = 0;
|
|
|
|
value = [[String alloc] initSCMString:buf];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMStrToList
|
|
- (NSString *)primName
|
|
{
|
|
return @"string->list";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+1!=[args count]){
|
|
errmsg = @"string->list takes one argument";
|
|
return NO;
|
|
}
|
|
|
|
String *str = [args objectAtIndex:offs];
|
|
if(isString(str)==NO){
|
|
errmsg = @"string->list: string required";
|
|
return NO;
|
|
}
|
|
|
|
NSString *theStr = [str strVal];
|
|
|
|
id result = [NSNull null];
|
|
int cmax = [theStr length], cpos;
|
|
|
|
cpos = cmax-1;
|
|
while(cpos>=0){
|
|
char c = [theStr characterAtIndex:cpos];
|
|
result =
|
|
[Pair
|
|
newCar:[[Char alloc] initSCMChar:c]
|
|
Cdr:result];
|
|
cpos--;
|
|
}
|
|
|
|
value = result;
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMStringAppend
|
|
- (NSString *)primName
|
|
{
|
|
return @"string-append";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
NSString *result = @"";
|
|
|
|
int cpos = offs, cmax = [args count];
|
|
while(cpos<cmax){
|
|
String *str = [args objectAtIndex:cpos];
|
|
if(isString(str)==NO){
|
|
errmsg = @"string-append: string required";
|
|
return NO;
|
|
}
|
|
|
|
result = [result stringByAppendingString:[str strVal]];
|
|
cpos++;
|
|
}
|
|
|
|
value = [[String alloc] initSCMString:(char *)[result cString]];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMMakeString
|
|
- (NSString *)primName
|
|
{
|
|
return @"make-string";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+1!=[args count] && offs+2!=[args count]){
|
|
errmsg = @"make-string takes one or two arguments";
|
|
return NO;
|
|
}
|
|
|
|
Int *i = [args objectAtIndex:offs];
|
|
if(isInt(i)==NO){
|
|
errmsg = @"make-string: integer required";
|
|
return NO;
|
|
}
|
|
int pos = 0, count = [i intVal];
|
|
|
|
char fill = ' ';
|
|
if(offs+2==[args count]){
|
|
Char *ch = [args objectAtIndex:offs+1];
|
|
if(isChar(ch)==NO){
|
|
errmsg = @"make-string: character required";
|
|
return NO;
|
|
}
|
|
fill = [ch charVal];
|
|
}
|
|
|
|
char buf[count+1];
|
|
while(pos<count){
|
|
buf[pos++] = fill;
|
|
}
|
|
buf[pos] = 0;
|
|
|
|
value = [[String alloc] initSCMString:buf];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMNumberToStr
|
|
- (NSString *)primName
|
|
{
|
|
return @"number->string";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs+1!=[args count] && offs+2!=[args count]){
|
|
errmsg = @"number->string takes one or two arguments";
|
|
return NO;
|
|
}
|
|
|
|
id n = [args objectAtIndex:offs];
|
|
if(isInt(n)==NO && isDouble(n)==NO){
|
|
errmsg = @"number->string: int or double required";
|
|
return NO;
|
|
}
|
|
|
|
if(isDouble(n)){
|
|
NSNumber *num = [NSNumber numberWithDouble:[n doubleVal]];
|
|
value = [[String alloc] initSCMString:(char *)[[num description] cString]];
|
|
return YES;
|
|
}
|
|
|
|
int radix = 10;
|
|
if(offs+2==[args count]){
|
|
Int *r = [args objectAtIndex:offs+1];
|
|
if(isInt(r)==NO){
|
|
errmsg = @"number->string: radix must be an integer";
|
|
return NO;
|
|
}
|
|
radix = [r intVal];
|
|
if(radix<2 || radix>36){
|
|
errmsg = @"number->string: radix must be >= 2 and <= 36";
|
|
return NO;
|
|
}
|
|
}
|
|
|
|
int number = [n intVal];
|
|
if(radix==10 || !number){
|
|
NSNumber *num = [NSNumber numberWithInt:number];
|
|
value = [[String alloc] initSCMString:(char *)[[num description] cString]];
|
|
return YES;
|
|
}
|
|
|
|
int sign = 1;
|
|
if(number<0){
|
|
sign = -1;
|
|
number = -number;
|
|
}
|
|
|
|
NSString *result = @"";
|
|
while(number>0){
|
|
int digit = number % radix;
|
|
result =
|
|
[[NSString stringWithFormat:@"%c",
|
|
(digit<10 ? '0' + digit : 'A' + digit-10)]
|
|
stringByAppendingString:result];
|
|
number /= radix;
|
|
}
|
|
|
|
if(sign==-1){
|
|
result = [NSString stringWithFormat:@"-%@", result];
|
|
}
|
|
|
|
value = [[String alloc] initSCMString:(char *)[result cString]];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMFormat
|
|
- (NSString *)primName
|
|
{
|
|
return @"format";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
if(offs==[args count]){
|
|
errmsg = @"format needs at least one argument";
|
|
return NO;
|
|
}
|
|
|
|
String *fmt = [args objectAtIndex:offs++];
|
|
if(isString(fmt)==NO){
|
|
errmsg = @"format: string required";
|
|
return NO;
|
|
}
|
|
const char *fmtStr = [[fmt strVal] cString];
|
|
|
|
NSString *result = @"";
|
|
while(*fmtStr){
|
|
NSString *item;
|
|
|
|
if(fmtStr[0]=='~'){
|
|
if(fmtStr[1]){
|
|
switch(fmtStr[1]){
|
|
case 'a':
|
|
case 's':
|
|
if(offs==[args count]){
|
|
errmsg = @"format: ran out of arguments";
|
|
return NO;
|
|
}
|
|
|
|
id cur = [args objectAtIndex:offs++];
|
|
if(isString(cur)){
|
|
item = [NSString stringWithFormat:@"%@", [cur strVal]];
|
|
}
|
|
else if(isChar(cur)){
|
|
item = [NSString stringWithFormat:@"%c", [cur charVal]];
|
|
}
|
|
else{
|
|
item = [VScheme valToString:cur];
|
|
}
|
|
break;
|
|
case '%':
|
|
item = @"\n";
|
|
break;
|
|
case '~':
|
|
item = @"~";
|
|
}
|
|
fmtStr++;
|
|
}
|
|
}
|
|
else{
|
|
item = [NSString stringWithCString:fmtStr length:1];
|
|
}
|
|
|
|
result = [result stringByAppendingString:item];
|
|
|
|
fmtStr++;
|
|
}
|
|
|
|
value = [[String alloc] initSCMString:(char *)[result cString]];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMBrowseEnvironment
|
|
- (NSString *)primName
|
|
{
|
|
return @"browse-environment";
|
|
}
|
|
|
|
- (BOOL)evalVM:(id)vm Args:(NSMutableArray *)args offset:(int)offs
|
|
{
|
|
id win;
|
|
|
|
if(offs!=[args count]){
|
|
errmsg = @"browse-environment takes no arguments";
|
|
return NO;
|
|
}
|
|
|
|
win = [[EnvWindow alloc] initWithEnv:[[vm envStack] lastObject]];
|
|
[[vm delegate] envWindow:win];
|
|
|
|
value = [NSNull null];
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation PRMEval
|
|
- (NSString *)primName
|
|
{
|
|
return @"eval";
|
|
}
|
|
|
|
@end
|