無料Wikiサービス | デモページ
Linuxなどのメモ書き

V8 JavaScriptエンジンの組み込み


概要

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()関数の実行が確認できた。


次は、グローバル空間への変数の追加を試す。

つづく。


最終更新 2012/08/30 10:10:05 - kztomita
(2012/08/28 20:29:24 作成)