V8 JavaScriptエンジンの組み込み
Rev.3を表示中。最新版はこちら。
概要
V8 JavaScriptエンジンの組み込みと関数等の追加を試した。
V8の組み込み
まずは標準入力からJavaScriptソースを読み込んで実行するケース。
https://developers.google.com/v8/get_startedに載っているものとほぼ同じで、ソースを標準入力から取得するように修正しただけ。このソースをベースに試していく。
#include <v8.h>
#include <iostream>
#include <string>
using namespace v8;
static void read_file(std::istream& ifs, std::string &content)
{
content = "";
std::string t;
while (!ifs.eof()) {
getline(std::cin, t);
content += t + "\n";
}
}
int main(int argc, char* argv[])
{
std::string js_str;
read_file(std::cin, js_str);
// Create a stack-allocated handle scope.
HandleScope handle_scope;
// Create a new context.
Persistent<Context> context = Context::New();
// Enter the created context for compiling and
// running the hello world script.
Context::Scope context_scope(context);
// Create a string containing the JavaScript source code.
Handle<String> source = String::New(js_str.c_str());
// Compile the source code.
Handle<Script> script = Script::Compile(source);
// Run the script to get the result.
Handle<Value> result = script->Run();
// Dispose the persistent context.
context.Dispose();
// Convert the result to an ASCII string and print it.
String::AsciiValue ascii(result);
printf("%s\n", *ascii);
return 0;
}
Build手順は省略。以下のtest.jsを読み込ませて実行してみると。
test.js
(function()
{
return "test test";
})();
実行結果
# ./a.out < test.js test test
関数のリターン値"test test"が表示される。これで、いろいろ試す準備が整った。
関数の追加
まず最初に関数を追加してみる。追加する関数はfunction log(str)で、引数に指定した文字列を標準出力に出力するログ出力関数。
関数を新たに作るにはテンプレート(C++のテンプレートとは別のもの)を使う。テンプレートには関数テンプレートとオブジェクトテンプレートがあるが、関数を作る場合は、関数テンプレートを使って関数実行時のコールバックルーチンを登録し、さらにオブジェクトテンプレートで関数名と関数テンプレートを関連付ける。
#include <v8.h>
#include <iostream>
#include <string>
using namespace v8;
static void read_file(std::istream& ifs, std::string &content)
{
content = "";
std::string t;
while (!ifs.eof()) {
getline(std::cin, t);
content += t + "\n";
}
}
// log()が呼ばれた時のコールバックルーチン
static Handle<Value> log_callback(const Arguments& args) {
if (args.Length() < 1)
return v8::Undefined();
HandleScope scope;
Handle<Value> arg = args[0];
String::Utf8Value value(arg);
std::cout << "log: " << *value << std::endl;
return v8::Undefined();
}
int main(int argc, char* argv[])
{
std::string js_str;
read_file(std::cin, js_str);
// Create a stack-allocated handle scope.
HandleScope handle_scope;
Handle<ObjectTemplate> global = ObjectTemplate::New();
// log()関数のコールバックを指定
global->Set(String::New("log"), FunctionTemplate::New(log_callback));
// Create a new context.
Persistent<Context> context = Context::New(NULL, global);
// Enter the created context for compiling and
// running the hello world script.
Context::Scope context_scope(context);
// Create a string containing the JavaScript source code.
Handle<String> source = String::New(js_str.c_str());
// Compile the source code.
Handle<Script> script = Script::Compile(source);
// Run the script to get the result.
Handle<Value> result = script->Run();
// Dispose the persistent context.
context.Dispose();
// Convert the result to an ASCII string and print it.
String::AsciiValue ascii(result);
printf("%s\n", *ascii);
return 0;
}
上記ソースではオブジェクトテンプレートに"log"という名前でlog_callback()関数を登録しているので、JavaScriptからlog()を実行するとlog_callback()が実行されることになる。log_callback()では、引数に渡された内容を標準出力に出力する。
以下のtest2.jsを読み込ませて実行してみると。
test2.js
log("test test");
実行結果
# ./a.out < test2.js log: test test <-- log()の実行結果 undefined <-- これはlog()がundefinedを返しているため。
log()関数の実行が確認できた。
次は、グローバル空間への変数の追加を試す。
つづく。
