summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile24
-rw-r--r--MLKForeignProcedure.h47
-rw-r--r--MLKForeignProcedure.m117
-rw-r--r--MLKInterpreter.m35
4 files changed, 212 insertions, 11 deletions
diff --git a/GNUmakefile b/GNUmakefile
index be541ef..7cc4350 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -29,6 +29,7 @@ ifeq ($(DEBUG),YES)
ADDITIONAL_OBJCFLAGS += -ggdb3
endif
+# I know, I know. I'm emulating ‘configure’ here. *shrug* Whatever.
HAVE_FFI_H := $(shell echo '\#include <ffi.h>' | $(CC) $(ADDITIONAL_OBJCFLAGS) -c -o /dev/null -x c - 2>/dev/null && echo YES)
ifeq ($(HAVE_FFI_H),YES)
@@ -48,20 +49,21 @@ ToiletKit_OBJC_FILES = functions.m globals.m MLKBackquoteReader.m \
MLKCompiledProcedure.m MLKCons.m MLKDoubleFloat.m \
MLKDispatchingMacroCharacterReader.m \
MLKDynamicContext.m MLKEnvironment.m MLKFloat.m \
- MLKInteger.m MLKInterpretedClosure.m \
- MLKInterpreter.m MLKLexicalContext.m \
- MLKLexicalEnvironment.m MLKLispValue.m \
- MLKNumber.m MLKPackage.m MLKParenReader.m \
- MLKQuoteReader.m MLKRatio.m MLKReader.m \
- MLKReadtable.m MLKReaderError.m MLKRoot.m \
- MLKSemicolonReader.m MLKSharpsignColonReader.m \
- MLKSingleFloat.m MLKStream.m \
- MLKStringInputStream.m MLKStringOutputStream.m \
- MLKStringReader.m MLKSymbol.m MLKThrowException.m \
+ MLKForeignProcedure.m MLKInteger.m \
+ MLKInterpretedClosure.m MLKInterpreter.m \
+ MLKLexicalContext.m MLKLexicalEnvironment.m \
+ MLKLispValue.m MLKNumber.m MLKPackage.m \
+ MLKParenReader.m MLKQuoteReader.m MLKRatio.m \
+ MLKReader.m MLKReadtable.m MLKReaderError.m \
+ MLKRoot.m MLKSemicolonReader.m \
+ MLKSharpsignColonReader.m MLKSingleFloat.m \
+ MLKStream.m MLKStringInputStream.m \
+ MLKStringOutputStream.m MLKStringReader.m \
+ MLKSymbol.m MLKThrowException.m \
MLKValuesFunction.m NSObject-MLKPrinting.m \
NSString-MLKPrinting.m
ToiletKit_OBJCFLAGS = -Wall
-ToiletKit_LDFLAGS = -lgmp -lffi
+ToiletKit_LDFLAGS = -lgmp -lffi -ldl
#LIBRARIES_DEPEND_UPON
#TOOL_NAME = etoilet
diff --git a/MLKForeignProcedure.h b/MLKForeignProcedure.h
new file mode 100644
index 0000000..d424de4
--- /dev/null
+++ b/MLKForeignProcedure.h
@@ -0,0 +1,47 @@
+/* -*- mode: objc; coding: utf-8 -*- */
+/* Toilet Lisp, 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 <http://www.gnu.org/licenses/>.
+ */
+
+#import "MLKFuncallable.h"
+#import "MLKLispValue.h"
+#import "MLKLexicalContext.h"
+#import "MLKLexicalEnvironment.h"
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSString.h>
+
+#import "functions.h"
+
+
+@interface MLKForeignProcedure : MLKLispValue <MLKFuncallable>
+{
+ void *_code;
+ MLKForeignType *_argumentTypes;
+ MLKForeignType _returnType;
+}
+
+-(id) initWithCode:(void *)code
+ argumentTypes:(NSArray *)argTypes
+ returnType:(id)returnType;
+
+-(NSArray *) applyToArray:(NSArray *)arguments;
+
+-(NSString *) description;
+-(NSString *) descriptionForLisp;
+
+-(void) dealloc;
+@end
diff --git a/MLKForeignProcedure.m b/MLKForeignProcedure.m
new file mode 100644
index 0000000..fa889cb
--- /dev/null
+++ b/MLKForeignProcedure.m
@@ -0,0 +1,117 @@
+/* -*- mode: objc; coding: utf-8 -*- */
+/* Toilet Lisp, 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 <http://www.gnu.org/licenses/>.
+ */
+
+#import "MLKForeignProcedure.h"
+#import "globals.h"
+#import "util.h"
+
+#import <Foundation/NSArray.h>
+#import <Foundation/NSEnumerator.h>
+
+#ifdef HAVE_FFI_H
+#include <ffi.h>
+#elif HAVE_FFI_FFI_H
+#include <ffi/ffi.h>
+#endif
+
+#include <stdlib.h>
+
+
+@implementation MLKForeignProcedure
+-(id) initWithCode:(void *)code
+ argumentTypes:(NSArray *)argTypes
+ returnType:(id)returnType
+{
+ int i;
+ NSEnumerator *e;
+ id el;
+
+ self = [super init];
+
+ _code = code;
+ _returnType = MLKForeignTypeWithTypeDesignator (returnType);
+
+ _argumentTypes = malloc (sizeof (MLKForeignType) * [argTypes count]);
+
+ e = [argTypes objectEnumerator];
+ i = 0;
+ while ((el = [e nextObject]))
+ {
+ _argumentTypes[i++] = MLKForeignTypeWithTypeDesignator (denullify (el));
+ }
+
+ return self;
+}
+
+-(NSArray *) applyToArray:(NSArray *)arguments
+{
+ int argc = [arguments count];
+ ffi_cif cif;
+ ffi_type *arg_types[argc];
+ ffi_type *return_type;
+ ffi_status status;
+ void *argv[argc];
+ id return_value;
+ int i;
+
+ for (i = 0; i < argc; i++)
+ {
+ arg_types[i] =
+ MLKFFITypeWithForeignType (_argumentTypes[i]);
+ argv[i] = alloca (arg_types[i]->size);
+ MLKSetForeignValueWithLispValue (argv[i],
+ [arguments objectAtIndex:i],
+ _argumentTypes[i]);
+ }
+
+ return_type = MLKFFITypeWithForeignType (_returnType);
+
+ status = ffi_prep_cif (&cif, FFI_DEFAULT_ABI, argc, return_type, arg_types);
+ if (status != FFI_OK)
+ {
+ [NSException raise:@"MLKInvalidFFITypeException"
+ format:@"FFI type is invalid (this is probably a bug)."];
+ }
+
+ ffi_call (&cif, FFI_FN (_code), &return_value, (void**)argv);
+
+ // FIXME
+ if (return_type == &ffi_type_void)
+ return [NSArray array];
+ else
+ return [NSArray arrayWithObject:nullify (MLKLispValueWithForeignValue (&return_value, _returnType))];
+}
+
+-(NSString *) description
+{
+ return MLKPrintToString(self);
+}
+
+-(NSString *) descriptionForLisp
+{
+ return [NSString stringWithFormat:@"<Compiled procedure @%p>", self];
+}
+
+-(void) dealloc
+{
+ // FIXME: Can we really just use free() here?
+ free (_code);
+ free (_argumentTypes);
+ [super dealloc];
+}
+@end
diff --git a/MLKInterpreter.m b/MLKInterpreter.m
index fcc0e84..64e23de 100644
--- a/MLKInterpreter.m
+++ b/MLKInterpreter.m
@@ -16,10 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define _XOPEN_SOURCE 600
+#define _GNU_SOURCE // for RTLD_DEFAULT
+#define _ISOC99_SOURCE
+
#import "MLKInterpretedClosure.h"
#import "MLKCons.h"
#import "MLKDynamicContext.h"
#import "MLKEnvironment.h"
+#import "MLKForeignProcedure.h"
#import "MLKFuncallable.h"
#import "MLKInterpreter.h"
#import "MLKLexicalContext.h"
@@ -37,6 +42,12 @@
#import <Foundation/NSNull.h>
#import <Foundation/NSString.h>
+#ifndef _WIN32
+#include <dlfcn.h>
+#else
+#include <windows.h>
+#endif
+
#include <stdio.h>
@@ -72,6 +83,7 @@ static MLKSymbol *PROGV;
static MLKSymbol *UNWIND_PROTECT;
static MLKSymbol *VALUES;
static MLKSymbol *_DEFMACRO;
+static MLKSymbol *_FOREIGN_LAMBDA;
static MLKSymbol *_LAMBDA;
static MLKSymbol *_LOOP;
static MLKSymbol *V_INITP;
@@ -120,6 +132,7 @@ static MLKSymbol *MULTIPLE_VALUE_CALL;
VALUES = [cl intern:@"VALUES"];
UNWIND_PROTECT = [cl intern:@"UNWIND-PROTECT"];
_DEFMACRO = [sys intern:@"%DEFMACRO"];
+ _FOREIGN_LAMBDA = [sys intern:@"%FOREIGN-LAMBDA"];
_LAMBDA = [sys intern:@"%LAMBDA"];
V_INITP = [sys intern:@"*SYSTEM-INITIALISED-P*"];
MULTIPLE_VALUE_CALL = [cl intern:@"MULTIPLE-VALUE-CALL"];
@@ -473,6 +486,28 @@ static MLKSymbol *MULTIPLE_VALUE_CALL;
}
}
}
+ else if (car == _FOREIGN_LAMBDA)
+ {
+ int (*function)();
+ NSString *name = [[program cdr] car];
+ id libraryDesignator = [[[program cdr] cdr] car];
+ id argtypes = [[[[program cdr] cdr] cdr] car];
+ id returnType = [[[[[program cdr] cdr] cdr] cdr] car];
+
+ // FIXME: Support library designators.
+
+#ifdef _WIN32
+ EnumProcessModules (...);
+ GetProcAddress (..., [name UTF8String]);
+#else
+ function = dlsym (RTLD_DEFAULT, [name UTF8String]);
+#endif
+
+ return LAUTORELEASE ([[MLKForeignProcedure alloc]
+ initWithCode:function
+ argumentTypes:[argtypes array]
+ returnType:returnType]);
+ }
else if (car == FUNCTION)
{
id functionName = [[program cdr] car];