/* -*- mode: objc; coding: utf-8 -*- */
/* Étoilisp/Mulklisp, a Common Lisp subset for the Étoilé runtime.
* Copyright (C) 2008 Matthias Andreas Benkard.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#import
#import
#import
#import
#import
#import "MLKCons.h"
#import "MLKDynamicContext.h"
#import "MLKEnvironment.h"
#import "MLKLinkedList.h"
#import "MLKPackage.h"
#import "MLKReadtable.h"
#import "MLKSymbol.h"
#import "MLKInteger.h"
#define MAKE_ENVIRONMENT(variable, parent, parent_member) \
(variable \
? (id) [[MLKEnvironment alloc] \
initWithParent:(parent \
? (id) parent_member \
: nil) \
bindings:vars] \
: (id) (parent ? (id) RETAIN (parent_member) : nil));
static MLKDynamicContext *global_context;
@implementation MLKDynamicContext
+(void) initialize
{
NSMutableDictionary *vars = [NSMutableDictionary dictionaryWithCapacity:64];
MLKPackage *cl = [MLKPackage packageWithName:@"COMMON-LISP"
nicknames:[NSSet setWithObject:@"CL"]];
MLKPackage *clUser = [MLKPackage packageWithName:@"COMMON-LISP-USER"
nicknames:[NSSet setWithObject:@"CL-USER"]];
MLKPackage *keyword = [MLKPackage packageWithName:@"KEYWORD"
nicknames:[NSSet set]];
MLKSymbol *t = [cl intern:@"T"];
MLKReadtable *readtable = [[MLKReadtable alloc] init];
id NIL = [NSNull null];
// FIXME: Initialise stuff.
#define INIT(VARNAME, VALUE) [vars setObject:VALUE forKey:[cl intern:VARNAME]]
INIT(@"*BREAK-ON-SIGNALS*", NIL);
INIT(@"*COMPILE-FILE-PATHNAME*", NIL);
INIT(@"*COMPILE-FILE-TRUENAME*", NIL);
INIT(@"*COMPILE-PRINT*", NIL);
INIT(@"*COMPILE-VERBOSE*", t);
// INIT(@"*DEBUG-IO*", );
INIT(@"*DEBUGGER-HOOK*", NIL);
// INIT(@"*DEFAULT-PATHNAME-DEFAULTS*", );
// INIT(@"*ERROR-OUTPUT*", );
INIT(@"*FEATURES*", [MLKCons
cons:[keyword intern:@"ETOILET"]
with:[MLKCons
cons:[keyword intern:@"COMMON-LISP"]
with:[MLKCons
cons:[keyword intern:@"ANSI-CL"]
with:nil]]]);
INIT(@"*GENSYM-COUNTER*", [MLKInteger integerWithInt:0]);
INIT(@"*LOAD-PATHNAME*", NIL);
INIT(@"*LOAD-PRINT*", NIL);
INIT(@"*LOAD-TRUENAME*", NIL);
INIT(@"*LOAD-VERBOSE*", t);
// INIT(@"*MACROEXPAND-HOOK*", );
INIT(@"*MODULES*", NIL);
INIT(@"*PACKAGE*", clUser);
INIT(@"*PRINT-ARRAY*", t);
INIT(@"*PRINT-BASE*", [MLKInteger integerWithInt:10]);
INIT(@"*PRINT-CASE*", [keyword intern:@"UPCASE"]);
INIT(@"*PRINT-CIRCLE*", NIL);
INIT(@"*PRINT-ESCAPE*", t);
INIT(@"*PRINT-GENSYM*", t);
INIT(@"*PRINT-LENGTH*", NIL);
INIT(@"*PRINT-LEVEL*", NIL);
INIT(@"*PRINT-LINES*", NIL);
INIT(@"*PRINT-MISER-WIDTH*", NIL);
// INIT(@"*PRINT-PPRINT-DISPATCH*", );
INIT(@"*PRINT-PRETTY*", t);
INIT(@"*PRINT-RADIX*", NIL);
INIT(@"*PRINT-READABLY*", NIL);
INIT(@"*PRINT-RIGHT-MARGIN*", NIL);
// INIT(@"*QUERY-IO*", );
// INIT(@"*RANDOM-STATE*", );
INIT(@"*READ-BASE*", [MLKInteger integerWithInt:10]);
INIT(@"*READ-DEFAULT-FLOAT-FORMAT*", [cl intern:@"SINGLE-FLOAT"]);
INIT(@"*READ-EVAL*", t);
INIT(@"*READ-SUPPRESS*", NIL); //FIXME: Support in reader
INIT(@"*READTABLE*", readtable);
// INIT(@"*STANDARD-INPUT*", );
// INIT(@"*STANDARD-OUTPUT*", );
// INIT(@"*TERMINAL-IO*", );
// INIT(@"*TRACE-OUTPUT* ", );
global_context = [[self alloc] initWithParent:nil
variables:vars
handlers:nil
restarts:nil
catchTags:nil
activeHandlerEnvironment:nil];
}
-(MLKDynamicContext *) initWithParent:(MLKDynamicContext *)aContext
variables:(NSDictionary *)vars
handlers:(NSDictionary *)handlers
restarts:(NSDictionary *)restarts
catchTags:(NSDictionary *)catchTags
activeHandlerEnvironment:(MLKEnvironment *)handlerEnv;
{
self = [super init];
ASSIGN (_parent, (aContext ? aContext : [MLKDynamicContext currentContext]));
_environment = MAKE_ENVIRONMENT(vars, _parent, _parent->_environment);
_conditionHandlers = MAKE_ENVIRONMENT(handlers,
_parent,
_parent->_conditionHandlers);
_restarts = MAKE_ENVIRONMENT(restarts, _parent, _parent->_restarts);
_catchTags = MAKE_ENVIRONMENT(catchTags, _parent, _parent->_catchTags);
ASSIGN (_activeHandlerEnvironment,
handlerEnv
? (id) handlerEnv
: (_parent
? (id) (_parent->_activeHandlerEnvironment)
: nil));
return self;
}
-(MLKDynamicContext *) pushContext
{
[[[NSThread currentThread] threadDictionary] setObject:self
forKey:@"MLKDynamicContext"];
return self;
}
+(MLKDynamicContext *) currentContext
{
MLKDynamicContext *context = [[[NSThread currentThread] threadDictionary]
objectForKey:@"MLKDynamicContext"];
if (context)
return context;
else
return global_context;
}
+(MLKDynamicContext *) popContext
{
MLKDynamicContext *context = [self currentContext];
[[[NSThread currentThread] threadDictionary] setObject:context->_parent
forKey:@"MLKDynamicContext"];
return context;
}
-(MLKEnvironment *) environment
{
return _environment;
}
-(id) findRestart:(MLKSymbol *)symbol
{
NS_DURING
{
return [_restarts valueForBinding:symbol];
}
NS_HANDLER
{
if ([[localException name] isEqualToString: @"MLKUndefinedVariableException"])
NS_VALUERETURN (nil, id);
else
[localException raise];
}
NS_ENDHANDLER;
return nil;
}
-(id) findHandler:(MLKSymbol *)symbol
{
NS_DURING
{
if (_activeHandlerEnvironment)
return [[_activeHandlerEnvironment parent] valueForBinding:symbol];
else
return [_conditionHandlers valueForBinding:symbol];
}
NS_HANDLER
{
if ([[localException name] isEqualToString: @"MLKUndefinedVariableException"])
NS_VALUERETURN (nil, id);
else
[localException raise];
}
NS_ENDHANDLER;
return nil;
}
-(id) findCatchTag:(MLKSymbol *)symbol
{
NS_DURING
{
return [_catchTags valueForBinding:symbol];
}
NS_HANDLER
{
if ([[localException name] isEqualToString: @"MLKUndefinedVariableException"])
NS_VALUERETURN (nil, id);
else
[localException raise];
}
NS_ENDHANDLER;
return nil;
}
-(id) valueForBinding:(MLKSymbol *)symbol
{
return [[self environment] valueForBinding:symbol];
}
-(void) setValue:(id)value forBinding:(MLKSymbol *)symbol
{
[[self environment] setValue:value forBinding:symbol];
}
-(void) addValue:(id)value forBinding:(MLKSymbol *)symbol
{
[[self environment] addValue:value forBinding:symbol];
}
-(void) addBinding:(MLKSymbol *)symbol
{
[[self environment] addBinding:symbol];
}
-(BOOL) boundp:(MLKSymbol *)symbol
{
return [[self environment] boundp:symbol];
}
-(void) makunbound:(MLKSymbol *)symbol
{
[[self environment] makunbound:symbol];
}
-(void) dealloc
{
RELEASE (_conditionHandlers);
RELEASE (_restarts);
RELEASE (_catchTags);
RELEASE (_activeHandlerEnvironment);
RELEASE (_environment);
RELEASE (_parent);
[super dealloc];
}
@end