- 1. 概要
- 2. libRedのビルド
- 3. 値の参照
- 4. C API
- 4.1. ライブラリの管理
- 4.2. Redのコードの実行
- 4.3. コールバック関数の登録
- 4.4. CからRedの値を作る
- 4.4.1. redSymbol()
- 4.4.2. redUnset()
- 4.4.3. redNone()
- 4.4.4. redLogic()
- 4.4.5. redDatatype()
- 4.4.6. redInteger()
- 4.4.7. redFloat()
- 4.4.8. redPair()
- 4.4.9. redTuple()
- 4.4.10. redTuple4()
- 4.4.11. redBinary()
- 4.4.12. redImage()
- 4.4.13. redString()
- 4.4.14. redWord()
- 4.4.15. redBlock()
- 4.4.16. redPath()
- 4.4.17. redLoadPath()
- 4.4.18. redMakeSeries()
- 4.5. Cの値をRedから作成する
- 4.6. Redのactionの呼び出し
- 4.7. Redのwordへのアクセス
- 4.8. Redのパスへのアクセス
- 4.9. Redのオブジェクトフィールドへのアクセス
- 4.10. デバッギング
- 4.11. データ型の定義
- 5. Visual Basic API
LibRedはRedのインタプリタとランタイムライブラリの特別なバージョンです。libRedはRed以外の言語でソフトウェアを開発する場合に適しています。RedではないソフトウェアがRedとやりとりすることを可能にするために、libRedはこのドキュメントに記載されている専用のローレベルAPIを(CのcdeclかMicrosoftのstadcallで)公開します。サポートされる機能は以下の通りです。
-
グローバルまたはローカルなコンテキストのwordへの値の設定と取得
-
最も一般的なRedのデータ型のコンストラクタへのショートカット
-
Cと互換のあるRedのデータ型に関する関数のコンバージョン
-
ホスト言語からのseriesの操作
-
Redがホスト言語の関数を呼び出し可能にするコールバック機能
-
コンソール向けのデバッグ関数
用語: ホスト という用語はホスト言語またはlibRedを組み込んだアプリケーションのことを指します。
libRedを使用したサンプルは こちら で確認することができます。
自身のローカル環境にlibRedをビルドする方法はシンプルです。
red build libRed
または、RebolコンソールとRedのソースで
rc "build libRed"
これらのコマンドラインはC言語用(cdeclのABIを使用する)libRedをビルドします。 もし(Microsoftアプリケーションとの互換のために)stdcall ABIが必要の場合、次のようにします。
red build libRed stdcall
libRedの関数呼び出しにより、Redの値が返されます。値は 不透明な 32ビットの参照で表現されます。これらの参照は短命で、別のlibRed関数の呼び出しに渡すなど、ローカルな使用に留めるべきです。ホストの変数にこれらの参照をセットすることは可能ですが、 セットしたら直ちに 使用すべきです。これらの参照は特別なメモリマネージャで管理され、約50回のAPI呼び出しの間しか生存しません。以下に例を記載します。
long a, blk; a = redSymbol("a"); redSet(a, redBlock(0)); // 返された参照は直後のこの箇所で使用されています。 blk = redGet(a); redPrint(blk); // 安全な参照の使用 for(i = 0; i < 100, i++) { // redAppend(blk, redNone()); // アンセーフな参照の使用です! redAppend(redGet("a"), redNone()); // 安全なバージョン }
C APIはC/C++のアプリケーションで使用することができます。また、その他のC互換 FFI を持つすべての言語とRedを統合することができます。
libRedの インスタンス は他の全てのAPIを使用するために必要です。
Note
|
現在のところ、1つのプロセス内で1つのlibRedセッションのみ許されます。複数インスタンスをサポートするように将来拡張される予定です。 |
void redOpen(void)
新しいRedのランタイムライブラリセッションを初期化します。この関数は 他のすべてのAPI関数を呼び出す前に 呼び出しされる必要があります。
Note
|
もしredOpenの実行前に他の関数が呼び出しされた場合、その関数の戻り値は「-2」になります。これは不適切なアクセスが試みられたことを示します。 |
ホストソフトウェアはRedのコードをダイレクトに実行できます。これにはいくつかの異なるコントロールレベルがあり、Redのコードの文字列を評価させたり、ホスト側で生成した引数をRedの関数に直接渡して呼び出しするといった方法があります。
red_value redDo(const char* source)
文字列として渡されたRedの式を評価し、最後のRedの値を戻り値として返します。
redDo("a: 123"); redDo("view [text {hello}]"); char *s = (char *) malloc(100); const char *caption = "Hello"; redDo(sprintf(s, "view [text \"%s\"]", caption));
red_value redDoFile(const char* filename)
filename で指定されたRedのスクリプトをロード、評価し、最後の値を返します。 filename はRedのOS非依存の規約(基本的にはUnixスタイルです)を使用してフォーマットされます。
redDoFile("hello.red"); redDoFile("/c/dev/red/demo.red");
red_value redDoBlock(red_block code)
引数のブロックを評価し、最後の値を返します。
redDoBlock(redBlock(redWord("print"), redInteger(42)));
Redで発生したイベントにレスポンスしたり、Redの呼び出しを(たとえば「print」や「ask」を)リダイレクトしたりするには、Redの側からホストの関数へコールバックする必要があります。これは「redRoutine()」関数を使うことで実現できます。
red_value redRoutine(red_word name, const char* spec, void* func_ptr)
name で指定された名前と、 spec をスペックブロック、 func-ptr で指定されたCの関数ポインタをボディとして、新しいRedのroutineを定義します。指定するCの関数は Redの値を返さなければなりません(戻り値が使われないことを示すために「redUnset()」を使うこともできます)。
#include "red.h" #include <stdio.h> red_integer add(red_integer a, red_integer b) { return redInteger(redCInt32(a) + redCInt32(b)); } int main(void) { redRoutine(redWord("c-add"), "[a [integer!] b [integer!]]", (void*) &add); printf(redCInt32(redDo("c-add 2 3"))); return 0; }
libRed APIの多くの関数は( references として)Redの値を渡す必要があります。以下の関数は最もよく使われるデータ型のシンプルなコンストラクタです。
long redSymbol(const char* word)
(Cのstringとして与えられた)ロードされた word に関連づけられたシンボルIDを返します。このIDはwordの値のの代わりにシンボルIDを必要とする他のlibRed API関数に渡すことができます。
long a = redSymbol("a"); redSet(a, redInteger(42)); printf("%l\n", redGet(a));
red_logic redLogic(long logic)
「logic!」型の値を返します。 logic の値が「0」であれば「false」、それ以外であれば「true」が戻り値となります。
red_datatype redDatatype(long type)
type で指定されたIDに対応する「datatype!」の値を返します。IDは「RedType」列挙体で定義されています。
red_tuple redTuple(long r, long g, long b)
3つのinteger値(通常はRGBカラーを表現するために使われます)を元に「tuple!」の値を返します。渡された引数は8ビット値に切り捨てられます。
red_tuple redTuple4(long r, long g, long b, long a)
4つのinteger値(通常はRGBカラーを表現するために使われます)を元に「tuple!」の値を返します。渡された引数は8ビット値に切り捨てられます。
red_binary redBinary(const char* buffer, long bytes)
指定されたメモリバッファのポインターとbytesで指定されたバッファの長さから binary!
の値を返します。受け取ったバッファは内部的にコピーされます。
red_image redImage(long width, long height, const void* buffer, long format)
指定されたメモリバッファのポインターから image!
の値を返します。イメージのサイズはピクセル単位の width
と height
で定義されます。受け取ったバッファは内部的にコピーされます。指定可能なバッファのフォーマットは以下です。
-
RED_IMAGE_FORMAT_RGB
: 24BPP(24-bit per pixel)のフォーマット -
RED_IMAGE_FORMAT_ARGB
: 32BPP(32-bit per pixel)とアルファチャンネルのフォーマット
red_string redString(const char* string)
string のポインタから「string!」の値を返します。引数の文字列に対してデフォルトではUTF-8エンコーディングであることが期待されます。他のエンコーディングを定義する場合、「redSetEncoding()」関数を使うことで行えます。
red_word redWord(const char* word)
Cのstringから「word!」の値を返します。引数の文字列に対してデフォルトではUTF-8エンコーディングが期待されます。他のエンコーディングを定義する場合、「redSetEncoding()」関数を使うことで行えます。wordとしてロードできない文字列が渡された場合、値「error!」が返されます。
red_block redBlock(red_value v,...)
引数のリストから新しいblock!のseriesを返します。リストは終わりを示すため、「null」か「0」で 終わらなければなりません。
redBlock(0); // 空のblockを生成 redBlock(redInteger(42), redWord("hi"), 0); // [42 hi] というblockを生成
red_path redPath(red_value v, ...)
引数のリストから新しいpath!のseriesを返します。リストは終わりを示すため、「null」か「0」で 終わらなければなりません。
redDo("a: [b 123]"); long res = redDo(redPath(redWord("a"), redWord("b"), 0); printf("%l\n", redCInt32(res)); // 「123」が出力されます。
red_path redLoadPath(const char* path)
Cの文字列として表現されたパスからpath!のseriesを返します。これにより、ここの要素を個別に生成することなく、簡単にパスを生成できます。
redDo(redLoadPath("a/b")); // a/bというpath!の値を生成して評価します。
red_value redMakeSeries(unsigned long type, unsigned long slots)
type で指定した型の新しいseries!を、 slots で指定した数の要素が入るサイズで生成します。これはseriesを生成する包括的な関数です。typeは RedType
列挙体の値のいずれかである必要があります。
redMakeSeries(RED_TYPE_PAREN, 2); // paren! seriesを生成します。 long path = redMakeSeries(RED_TYPE_SET_PATH, 2); // set-path!を生成します。 redAppend(path, redWord("a")); redAppend(path, redInteger(2)); // pathが `a/2:` に更新されます。
Redの値をホストの側へ変換することは可能ですが、C言語のいくつかのデータ型に限られます。
const char* redCString(red_string string)
Redのstring!の値からUTF-8の文字列バッファポインタを返します。他のエンコーディングは redSetEncoding
関数で指定できます。
long redTypeOf(red_value value)
Redの値の型IDを返します。型IDは RedType
列挙体で定義されています。データ型 セクションを参照してください。
redCall
を使用することですべてのRedの関数を呼び出しすることができます。ただし、最もよく使われるactionには利便性とパフォーマンスのためいくつかのショートカットが提供されています。
red_value redAppend(red_series series, red_value value)
value を series に追加し、先頭位置をポイントするseriesを返します。
red_value redChange(red_series series, red_value value)
series の値を value で変更し、変更した箇所以降のseriesを返します。
red_value redClear(red_series series)
series の値を現在のインデックスから末尾まで削除し、新しい末尾位置のseriesを返します。
red_value redFind(red_series series, red_value value)
value が見つかった位置の series を返すか、NONEを返します。
red_value redIndex(red_series series)
先頭から見た_series_ のインデックスまたはコンテキスト中のwordのインデックスを返します。
red_value redMake(red_value proto, red_value spec)
spec と proto の型から、新しい値を作成して返します。
red_value redPick(red_series series, red_value value)
series の指定したインデックスの value を返します。
red_value redPoke(red_series series, red_value index, red_value value)
series の指定したインデックスの value を置き換え、新しい値を返します。
red_value redPut(red_series series, red_value index, red_value value)
series の指定したキーに対応する値を置き換え、新しい値を返します。
red_value redSelect(red_series series, red_value value)
series の中の value を探し、見つかればその次の値、見つからなければNONEを返します。
red_value redSkip(red_series series, red_integer offset)
現在のインデックスから指定の数だけ移動した series を返します。
RedのwordのセットやRedのwordからの値の取得はホストとRedのランタイム環境との間で値をやり取りする最も直接的な方法です。
red_value redSet(long id, red_value value)
id シンボルで指定されたwordに value の値をセットします。これによって作成されたwordはグローバルコンテキストに作成されます。 value はこの関数によって返される値になります。
パスはRedのデータにアクセスできる非常にフレキシブルな方法です。そのため、libRedにおいて専用のアクセス方法があります。とりわけ、それはオブジェクトコンテキスト内のwordへのアクセスを可能にします。
red_value redSetPath(red_path path, red_value value)
path に value をセットし、その value を返します。
オブジェクトのフィールドへの複数のセット/ゲットアクセスが必要な場合、パスを構築するよりもオブジェクトの値を直接使用する方がシンプルで木の間いいことがあります。以下の2つの関数はそのようなアクセスを可能にするために用意されています。
Note
|
これらのアクセサは object! 型だけでなく、関連付けされた他の配列型にも機能します。従って map! の値に対して使うことも可能です。
|
red_value redSetField(red_value object, long field, red_value value)
object の field に value をセットし、その value を返します。 field 引数は redSymbol()
によって作られたシンボルIDです。
いくつかの便利なデバッグ機能も提供されています。ほとんどは出力のためにシステムシェルウィンドウを必要としますが、ログウィンドウを強制的に開いたり、ファイルに出力をリダイレクトすることもできます。
red_value redProbe(red_value value)
標準出力化、もし開かれている場合はデバッグコンソールに value をprobeした値を出力します。 value はこの関数呼び出しの戻り値になります。
red_value redHasError(void)
直前のAPI呼び出しでエラーが発生していれば error! の値を、エラーが起きていなければ null
を返します。
const char* redFormError(void)
エラーが起きていれば フォーマットされたエラーを含むUTF-8の文字列ポインタを、エラーが起きていなければ null
を返します。
int redOpenLogWindow(void)
ログウィンドウを開き、全てのRedのprint出力をそのウィンドウにリダイレクトします。この機能はホストアプリケーションがデフォルトのprint出力先であるシステムシェルから起動されていない場合に役に立ちます。すでにログウィンドウが開いている場合、この関数を複数回読んでも、何も起こりません。戻り値は成功すれば「1」、失敗した場合は「0」です。
Note
|
Windowsプラットフォームでのみ有効です。 |
int redCloseLogWindow(void)
ログウィンドウを閉じます。ログウィンドウがすでに閉じている状況でこの関数を呼んでも何も起こりません。戻り値は成功すれば「1」、失敗した場合は「0」です。
Note
|
Windowsプラットフォームでのみ有効です。 |
void redOpenLogFile(const string *name)
name で指定されたファイルにRedのprint関数の出力をリダイレクトします。 name にはOSに応じたパス形式で、相対パス、仮想パスを指定することができます。
libRed APIのいくつかの関数はRedのデータ型を参照します。具体的には redTypeOf
、redMakeSeries()
、`redDataType()`です。Redのデータ型はホストの側で`RedType`列挙体として表現され、次の命名規則で型を示します。
RED_TYPE_<DATATYPE>
網羅的なリストは ここ で見つかります。
VBとVBA(MS Office アプリケーション上)のためのVisual Basic APIが用意されています。これは基本的にはC APIと同等で、以下のセクションに記載の内容だけが異なります。差異のほとんどは可変長引数に関係するもので、以下の2つに分類できます。
-
redBlock()
,redPath()
,redCall()
はRedの値だけを受け取ることができ、Cのバージョンのようにnull
または0
で終わることを必要としません。 -
redBlockVB()
,redPathVB()
,redCallVB()
はVBの値だけを受け取ることができ、次に示すテーブルの内容で自動的に変換が行われます。
VisualBasic | Red |
---|---|
|
|
|
|
|
|
|
|
|
|
VBおよびVBAでlibRedを使用するためには、 stdcall
のABIでコンパイルされたlibRedのバイナリが必要です。コンパイルするには、以下のコマンドを実行します。
red build libRed stdcall
また、 libRed.bas
モジュールをプロジェクトにインポートする必要もあります。
Function redLogic(bool As Boolean) As Long
VBの boolean
の値から Redの logic!
の値を生成して返します。
Function redBlockVB(ParamArray args() As Variant) As Long
引数のリストから新しいblock!を生成して返します。引数の数は可変であり、VisualBasicの値だけで構成されている必要があります。
redProbe redBlockVB() ' 空のブロックを生成します。 redProbe redBlockVB(42, "hello") ' [42 "hello"] というブロックを生成します。
Function redPathVB(ParamArray args() As Variant) As Long
引数のリストから新しいpath!のseriesを返します。引数の数は可変であり、VisualBasicの値だけで構成されている必要があります。
redDo("a: [b 123]") res = redDo(redPathVB("a", "b")) Debug.print redCInt32(res)) ' 123を出力します。
Function redCallVB(ParamArray args() As Variant) As Long
第一引数として渡された文字列で参照される any-function!
型のRedの関数に、任意の数の引数を渡して実行します。引数の数は可変であり、VisualBasicの値である必要があります。
redCallVB("random", 6); ' 1から6までのランダムなinteger!の値を返します。
Redの側から呼び出されることができるVisualBasicの関数を作る時は、C APIの場合と同様、 redRoutine()
を呼び出します。その関数の最後の引数は関数のポインタです。VBではそのようなポインタは module で定義された関数の場合のみ取得でき、 UserForm では取得できません。
以下はExcelの「Red Console」デモで使用されているコールバックです。
Sub RegisterConsoleCB() redRoutine redWord("print"), "[msg [string!]]", AddressOf onConsolePrint End Sub Function onConsolePrint(ByVal msg As Long) As Long If redTypeOf(msg) <> red_unset Then Sheet2.AppendOutput redCString(msg) onConsolePrint = redUnset End Function