naoya_t:MacOSX:Gauche.frameworkを使おう
作り方 → naoya_t:MacOSX:Gauche.frameworkを作ろう
Xcodeでプライベート・フレームワークを追加する方法
インクルードパス
#include "gauche.h"
ではなく
#include <Gauche/gauche.h>
のようにしないといけない点に注意。
※以下の例では
#define GAUCHE_API_0_8_8 YES #define GAUCHE_API_0_9 YES #include <Gauche/gauche.h>
みたいにして新APIを有効にしてます
初期化
...
GC_INIT();
Scm_Init(GAUCHE_SIGNATURE);
/* load_gauche_init() */
ScmLoadPacket lpak;
if (Scm_Load("gauche-init.scm", 0, &lpak) < 0) {
Scm_Printf(SCM_CURERR, "gosh: WARNING: Error while loading initialization file: %A(%A).\n",
Scm_ConditionMessage(lpak.exception),
Scm_ConditionTypeName(lpak.exception));
}
...
gauche-init.scm を読まなくても別に動くんだけど、(use module) マクロとか便利だから読んでおいたほうが良いよ。 というか、なんで (use srfi-1) とか出来ないの?とか悩むことになるよ
Schemeファイルの読み込み
...
ScmLoadPacket packet;
Scm_Load(path, 0, &packet);
...
上の gauche-init 読み込みにも出てきた Scm_Load() を使う。
ファイルが探索されるパス (*load-path*) に注意。デフォルトでは、Gauche.framework※の中の
- Versions/Current/share/gauche/site/lib
- Versions/Current/share/gauche/0.8.13/lib
以下が探索される。Scm_Load("hoge", 0, &packet) とすれば
- Versions/Current/share/gauche/site/lib/hoge.scm
- Versions/Current/share/gauche/0.8.13/lib/hoge.scm
の順に探索されて最初に見つかったファイルがロードされる。
※Gauche.framework は、ほげほげ.app/Contents/Frameworks/ の中にあります
ScmStringとNSStringの相互変換
カテゴリによるNSString拡張実装例。 ※使いたいところで #import <NSStringScmComponents.h>
NSStringScmComponents.h:
#import <Cocoa/Cocoa.h> #include <Gauche/gauche.h> @interface NSString (ScmComponents) - (id)initWithScmString:(ScmString *)scmStr; - (ScmObj)scmString; - (ScmObj)scmSymbol; + (id)stringWithScmString:(ScmString *)scmStr; @end
NSStringScmComponents.m:
#import <Foundation/NSString.h>
#import "NSStringTZComponents.h"
@implementation NSString (ScmComponents)
- (id)initWithScmString:(ScmString *)scmStr
{
if (self = [super init]) {
return [self initWithUTF8String:Scm_GetString(scmStr)];
}
return nil;
}
- (ScmObj)scmString
{
return SCM_MAKE_STR_COPYING([self UTF8String]);
// これを ScmString* にキャストするには SCM_STRING([foo scmString])
}
- (ScmObj)scmSymbol
{
return SCM_INTERN([self UTF8String]);
// ≡ Scm_Intern(SCM_STRING(SCM_MAKE_STR_IMMUTABLE([self UTF8String])))
// これを ScmSymbol* にキャストするには SCM_SYMBOL([foo scmSymbol])
}
+ (id)stringWithScmString:(ScmString *)scmStr
{
NSString *nsstr = [[NSString alloc] initWithScmString:scmStr];
return nsstr ? [nsstr autorelease] : nil;
}
@end
evalとかapplyとか
コード例:
#include <stdarg.h>
// C文字列を与えるとevalしてくれる
ScmObj gosh_eval_cstr( const char *cstr )
{
ScmEvalPacket packet;
int numVals = Scm_EvalCString(cstr, SCM_OBJ(Scm_UserModule()), &packet);
if (numVals < 0)
return packet.exception;
else
return (packet.numResults >= 1) ? packet.results[0] : SCM_UNDEFINED;
}
// gosh - sprintf()で組み立てたC文字列をevalに渡してくれる
ScmObj gosh( const char *format, ... )
{
char *buf;
va_list ap;
va_start(ap, format);
if (vasprintf(&buf, format, ap) < 0) {
NSLog(@"cannot allocate sufficient memory for vasprintf()");
}
va_end(ap);
if (buf) {
ScmObj result = gosh_eval_cstr( buf );
free(buf);
return result;
} else {
return SCM_UNDEFINED;
}
}
// Scm_Applyの旧APIと同じか
ScmObj gosh_apply( ScmObj proc, ScmObj args )
{
ScmEvalPacket packet;
int numVals = Scm_Apply(proc, args, &packet);
if (numVals < 0)
return packet.exception;
else
return (packet.numResults >= 1) ? packet.results[0] : SCM_UNDEFINED;
}
// writeで文字列化しているだけ
char *gosh_obj2cstr( ScmObj obj )
{
ScmObj oport = Scm_MakeOutputStringPort(TRUE);
Scm_Write(obj, oport, SCM_WRITE_DISPLAY);
ScmObj scm_str = Scm_GetOutputString(SCM_PORT(oport), 0);
char *str = Scm_GetString(SCM_STRING(scm_str)); // this is copy
Scm_ClosePort(SCM_PORT(oport));
oport = NULL;
return str;
}
...
gosh("(define (f x) (* x x x))");
gosh("(print (f 3))"); // コンソールに 27 が表示される
...
ScmObj g = gosh("(lambda (x y) (+ (* x x) y))"); // g にクロージャが得られる
ScmObj result = gosh_apply(g, Scm_List( SCM_MAKE_INT(3),
SCM_MAKE_INT(2),
NULL ) ); //★ ← Scm_List は引数の最後に NULL を書かないとエラー。SCM_NILではない。
if (result != SCM_UNDEFINED) {
NSLog(@"result of ScmApply: %d", SCM_INT_VALUE(result)); //→ 11
}
...