アプリに組み込む
このガイドでは、既存のWebアプリにAiScriptを組み込む方法をご紹介します。
1. AiScriptのインストール
まずは、AiScriptをインストールします。
# npm
npm i @syuilo/aiscript
# yarn
yarn add @syuilo/aiscript
# pnpm
pnpm add @syuilo/aiscript2. AiScriptの読み込み・設定
今回は、このようにテキストベースで渡されたAiScriptを実行するまでの手順を説明します。
const program = "<: \"Hello, World!\"";AiScriptを読み込みます。
import { Parser, Interpreter, utils } from '@syuilo/aiscript';
const program = "<: \"Hello, World!\"";AiScriptは、まずParserでASTと呼ばれるオブジェクトに変換し、その後Interpreterで実行します。
AiScriptを実行する際に呼び出すJavascript関数を用意しましょう。
AiScriptインタプリタの実行は非同期で行われますので、async functionを使用します。
import { Parser, Interpreter, utils } from '@syuilo/aiscript';
const program = "<: \"Hello, World!\"";
async function run() {
// 処理を追加していく
}
run(); 次に、ParserとInterpreterを初期化します。それぞれは再使用が可能なので、関数の外で宣言しておくとよいでしょう。
import { Parser, Interpreter, utils } from '@syuilo/aiscript';
const program = "<: \"Hello, World!\"";
let parser: Parser;
let interpreter: Interpreter;
async function run() {
parser = new Parser();
interpreter = new Interpreter();
}
run();Interpreterには、AiScriptにグローバル定数や関数を注入できるオプションと、入出力のためのハンドラがあります。
今回は、Interpreterの出力ハンドラからconsole.logを利用して、AiScriptからの出力をコンソールに表示するようにします。
AiScriptインタプリタとのやり取りでは生のJavascriptの値は使われず、すべてValueというオブジェクトを介しています。今回は簡単のために、utils.valueToJsを使ってValueをJavascriptの値に変換しています。
import { Parser, Interpreter, utils } from '@syuilo/aiscript';
const program = "<: \"Hello, World!\"";
let parser: Parser;
let interpreter: Interpreter;
async function run() {
parser = new Parser();
interpreter = new Interpreter({}, { // ←第1引数で注入する値を指定できる
out: (value) => {
console.log(utils.valueToJs(value));
},
});
}
run();これでParserとInterpreterの準備は完了です。実際にprogramを実行してみましょう。
import { Parser, Interpreter, utils } from '@syuilo/aiscript';
const program = "<: \"Hello, World!\"";
let parser: Parser;
let interpreter: Interpreter;
async function run() {
parser = new Parser();
interpreter = new Interpreter({}, {
out: (value) => {
console.log(utils.valueToJs(value));
},
});
const ast = parser.parse(program);
await interpreter.exec(ast);
}
run();お疲れ様でした!コンソールにHello, World!と表示されるはずです。
注意
実際の運用では、parser.parseおよびinterpreter.execにエラーハンドリングを追加してください。
3. 独自の値を注入する
先ほど説明した通り、Interpreterの第1引数にはAiScriptからアクセス可能なグローバル定数や関数を注入できます。
今回は、以下のような関数を注入してみましょう。
APP_VERSION: アプリケーションのバージョンの定数App:showAlert(message: string): アラートを表示する関数
そして、これらを組み合わせて、バージョン番号を含むアラートを表示するプログラムを実行してみます。
App:showAlert(`You are running MyApp Version {APP_VERSION}`)ステップ2のコードをそのまま流用して、AiScriptプログラムだけを変更したのが以下のものです。
import { Parser, Interpreter, utils } from '@syuilo/aiscript';
const program = `App:showAlert(\`You are running MyApp Version {APP_VERSION}\`)`;
let parser: Parser;
let interpreter: Interpreter;
async function run() {
parser = new Parser();
interpreter = new Interpreter({}, {
out: (value) => {
console.log(utils.valueToJs(value));
},
});
const ast = parser.parse(program);
await interpreter.exec(ast);
}
run();ここで、APP_VERSIONとApp:showAlertを注入します。
import { Parser, Interpreter, utils, values } from '@syuilo/aiscript';
import { alert } from '@/ui'; // お使いの環境に合わせて変更してください
const program = `App:showAlert(\`You are running MyApp Version {APP_VERSION}\`)`;
let parser: Parser;
let interpreter: Interpreter;
async function run() {
parser = new Parser();
interpreter = new Interpreter({
APP_VERSION: values.STR('1.0.0'),
'App:showAlert': values.FN_NATIVE(([message]) => {
utils.assertString(message);
alert(message.value);
return values.NULL;
}),
}, {
out: (value) => {
console.log(utils.valueToJs(value));
},
});
const ast = parser.parse(program);
await interpreter.exec(ast);
}
run();Interpreterの第1引数に、注入したい値をAiScriptの値に変換して渡します。すべての値はvaluesオブジェクトを通じて生成できます。もちろん文字列だけでなく、数値・配列・オブジェクトなども注入することができます。
また、関数の引数もAiScriptの値として渡されます。utilsに含まれているassert*系の関数を使って、型アサーションを行うとともに、不正な値が含まれていた場合はエラーを返すことができます。
ヒント
既存の関数群との衝突を避けるためにも、名前空間を意識して関数名を指定することをお勧めします。
独自関数を多数実装しているMisskeyの独自関数のリファレンスや、実際に独自関数を実装している部分のコードが参考になるでしょう。