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 } ...