diff options
| -rw-r--r-- | GNUmakefile | 24 | ||||
| -rw-r--r-- | MLKForeignProcedure.h | 47 | ||||
| -rw-r--r-- | MLKForeignProcedure.m | 117 | ||||
| -rw-r--r-- | MLKInterpreter.m | 35 | 
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]; | 
