Встраиваем JavaScript в Си приложение

Не так давно вышла свежая версия JS движка Duktape.
И наверное многим стоит о ней узнать. Библиотека компактна! Всего три файла. Но эти три файла позволят Вам встроить полноценный интерпретатор JavaScript в Ваше приложение на Си.

Для начала работы Вам нужно добавить в проект 3 файла: duktape.c, duktape.h и duk_config.h.

Библиотека действительно легковесна.

x86 default x86 lowmem x86 full lowmem
Code 170kB 150kB 200kB
Startup RAM 68kB 35kB 4kB

Простейшее приложение

#include "duktape.h"

int main()
{
	duk_context *ctx = duk_create_heap_default();
	if (ctx) {
		duk_eval_string(ctx, "print('Hello world from Javascript!', 5);");
		duk_destroy_heap(ctx);
	}
	return 0;
}

При выполнении Вы увидите сообщение.

Загрузка JavaScript файла

Но не всегда удобно держать JavaScript в си строке. Ведь мы скорее всего хотим делать дополнения или систему скриптования для нашего приложения.
На этот случай в Duktape есть возможность загрузить файл.

Создадим файл process.js в который поместим функцию process, которую потом вызовем из Си кода.

// process.js
function process(arg, arg2) {
    print(arg, arg2);
    return "Hi, there";
}

Как видно эта функция принимает 2 параметра, выводит их в консоль и возвращает строку "Hi, there".

#include "duktape.h"

int main()
{
	duk_context *ctx = duk_create_heap_default();

	if (duk_peval_file(ctx, "process.js") != 0) {
		printf("Error: %s\n", duk_safe_to_string(ctx, -1));
		duk_destroy_heap(ctx);
		return 1;
	}
	duk_pop(ctx);

	duk_push_global_object(ctx);


	//get js function, set it parameter and call
	duk_get_prop_string(ctx, -1 /*index*/, "process");

	duk_push_number(ctx, 123);
	duk_push_string(ctx, "foo");

	if (duk_pcall(ctx, 2 /*nargs*/) != 0) {
		printf("Error: %s\n", duk_safe_to_string(ctx, -1));
	}
	else {
		//print result
		printf("%s\n", duk_safe_to_string(ctx, -1));
	}
	duk_pop(ctx);  /* pop result/error */
	duk_destroy_heap(ctx);
    return 0;
}

Как и в предыдущем примере здесь мы создаем кучу для js движка, затем загружаем содержимое файлы process.js и создаем глобальный контекст.
Вся работа с Js строится на использовании стека значений. Таким образмо нам нужно выбрать функцию, которую мы хотим вызвать, а затем протолкнуть в стек параметры для неё. Когда это сделано вызываем фунцию при помощи duk_pcall. Эта функция принимает в качестве второго аргумента - количество параметров вызываемой функции.
Если все прошло успешно, мы можем получить возвращенный результат при помощи вызова duk_safe_to_string.

Си функции в JavaScript

Также имеется возможность выполнять nativ функции из JavaScript.
Создадим функцию, которая возвращает квадрат числа, которое передано ей как параметр.

duk_ret_t my_native_func(duk_context *ctx) {
	double arg = duk_require_number(ctx, 0 /*index*/);
	duk_push_number(ctx, arg * arg);
	return 1;
}

Теперь нам нужно зарегистрировать её.

duk_push_c_function(ctx, my_native_func, 1);
duk_put_prop_string(ctx, -2, "nativ_func");

Теперь функцию nativ_func можно вызывать из js кода.
Например так:

print("Native function returned: ", nativ_func(5))

Результат:

Скачать тестовый проект.

Просмотров:   1062

Комментарии

Добавить комментарий

Plain text

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и параграфы переносятся автоматически.
CAPTCHA
Введи эти символы. Ато роботы одолели!