1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/mirrors-chaiscript

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
cheatsheet.md 20 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 26.11.2024 16:44 334e279

ChaiScript: управление версиями

ChaiScript старается следовать схеме семантического управления версиями Semantic Versioning. Это означает, что:

  • основной номер версии (major version number) обозначает изменения API или критические изменения;
  • дополнительный номер версии (minor version number) — новые функции;
  • номер исправления (patch version number) — незначительные изменения и улучшения.

Инициализация ChaiScript

chaiscript::ChaiScript chai; // инициализирует ChaiScript, добавляя стандартные типы ChaiScript (map, string и т. д.)

Обратите внимание, что ChaiScript нельзя использовать как глобальный/статический объект, если он не компилируется с помощью CHAISCRIPT_NO_THREADS.

Добавление элементов в движок

Добавление функции/метода/члена

  1. Общее
chai.add(chaiscript::fun(&function_name), "function_name");
chai.add(chaiscript::fun(&Class::method_name), "method_name");
chai.add(chaiscript::fun(&Class::member_name), "member_name");
  1. Связанные методы-члены
chai.add(chaiscript::fun(&Class::method_name, Class_instance_ptr), "method_name");
chai.add(chaiscript::fun(&Class::member_name, Class_instance_ptr), "member_name");
  1. С перегрузками

Предпочтительный способ

chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");

Альтернативный способ

chai.add(chaiscript::fun(static_cast<ReturnType (*)(ParamType1, ParamType2)>(&function_with_overloads)), "function_name");

Этот метод перегрузки также используется при раскрытии базовых членов с использованием производного типа

struct Base
{
  int data;
};

struct Derived : public Base
{};

chai.add(chaiscript::fun(static_cast<int(Derived::*)>(&Derived::data)), "data");
  1. Лямбда
chai.add(
  chaiscript::fun<std::function<std::string (bool)>>(
    [](bool type) {
      if (type) { return "x"; }
      else { return "y"; }
    }), "function_name");
  1. Конструкторы
chai.add(chaiscript::constructor<MyType ()>(), "MyType");
chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");

Добавление типов Строго говоря, добавлять типы необязательно, но это помогает во многих ситуациях. Например, клонирование, улучшение сообщений об ошибках и т.д.

chai.add(chaiscript::user_type<MyClass>(), "MyClass");

Добавление преобразований типов Пользовательские преобразования типов возможны, определяются либо в скрипте, либо на C++.

  1. Определяемые ChaiScript преобразования Объекты-функции (включая лямбды) можно использовать для добавления преобразований типов из ChaiScript:
add_type_conversion(type("string"), type("Type_Info"), fun(s) { return type(s); });
  1. Определяемые C++ преобразования Вызов преобразования типа C++ возможен с помощью static_cast
chai.add(chaiscript::type_conversion<T, bool>());

Вызов пользовательского преобразования типа, которое принимает лямбда-выражение

chai.add(chaiscript::type_conversion<TestBaseType, Type2>([](const TestBaseType &t_bt) { /* return converted thing */ }));
  1. Иерархии классов Если вы хотите, чтобы объекты были конвертируемыми между базовыми и производными классами, вы должны сообщить об этом ChaiScript.
chai.add(chaiscript::base_class<Base, Derived>());

Если у вас есть несколько классов в вашем графе наследования, вы, вероятно, захотите сообщить ChaiScript обо всех отношениях.

chai.add(chaiscript::base_class<Base, Derived>());
chai.add(chaiscript::base_class<Derived, MoreDerived>());
chai.add(chaiscript::base_class<Base, MoreDerived>());
  1. Вспомогательные функции Существует вспомогательная функция для строго типизированных и ChaiScript Vector функций определения преобразования:
chai.add(chaiscript::vector_conversion<std::vector<int>>());

Также существует вспомогательная функция для строго типизированных и ChaiScript Map функций определения преобразования:

chai.add(chaiscript::map_conversion<std::map<std::string, int>>());

Это позволяет передавать функцию ChaiScript функции, требующей std::vector<int>

Добавление объектов

chai.add(chaiscript::var(somevar), "somevar"); // копируется
chai.add(chaiscript::var(std::ref(somevar)), "somevar"); // по ссылке, совместно используется C++ и chai
auto shareddouble = std::make_shared<double>(4.3);
chai.add(chaiscript::var(shareddouble), "shareddouble"); // через shared_ptr
``` **Добавление имён пространств имён**

Имена пространств имён не будут заполняться до тех пор, пока не будет вызван `import`. Это экономит память и вычислительные затраты, если пространство имён не импортируется в каждый экземпляр ChaiScript.

```cpp
chai.register_namespace([](chaiscript::Namespace& math) {
    math["pi"] = chaiscript::const_var(3.14159);
    math["sin"] = chaiscript::var(chaiscript::fun([](const double x) { return sin(x); })); },
    "math");

Импортируйте пространство имён в ChaiScript:

import("math")
print(math.pi) // печатает 3.14159

Использование STL ChaiScript распознаёт многие типы из STL, но вы должны добавить конкретную реализацию самостоятельно.

typedef std::vector<std::pair<int, std::string>> data_list;
data_list my_list{ make_pair(0, "Hello"), make_pair(1, "World") };
chai.add(chaiscript::bootstrap::standard_library::vector_type<data_list>("DataList"));
chai.add(chaiscript::bootstrap::standard_library::pair_type<data_list::value_type>("DataElement"));
chai::add(chaiscript::var(&my_list), "data_list");
chai.eval(R"_(
    for(var i=0; i<data_list.size(); ++i)
    {
      print(to_string(data_list[i].first) + " " + data_list[i].second)
    }
  )_");

Выполнение скрипта

Общие сведения

chai.eval("print(\"Hello World\")");
chai.eval(R"(print("Hello World"))");

Распаковка возвращаемых значений

Возвращаемые значения имеют тип Boxed_Value, который должен быть непрозрачным для программиста. Используйте один из методов распаковки для доступа к внутренним данным.

Предпочтительный метод

chai.eval<double>("5.3 + 2.1"); // возвращает 7.4 как C++ double

Альтернативный метод

auto v = chai.eval("5.3 + 2.1");
chai.boxed_cast<double>(v); // извлекает значение double из boxed_value и применяет известные преобразования
chaiscript::boxed_cast<double>(v); // бесплатная версия функции, не знает о преобразованиях

Преобразование между алгебраическими типами

chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // работает с любым числовым типом
// что эквивалентно, но гораздо более автоматизировано, чем:
static_cast<int>(chai.eval<double>("5.3+2.1")); // эта версия работает только в том случае, если мы знаем, что это double

Предостережения при преобразовании

Преобразование в std::shared_ptr<T> & поддерживается для вызовов функций, но если вы попытаетесь сохранить ссылку на shared_ptr<>, вы можете вызвать неопределённое поведение.

// ok, это поддерживается, вы можете зарегистрировать его в движке chaiscript
void nullify_shared_ptr(std::shared_ptr<int> &t) {
  t = nullptr
}
int main()
{
  // делаем некоторые вещи и создаём экземпляр chaiscript
  std::shared_ptr<int> &ptr = chai.eval<std::shared_ptr<int> &>(somevalue);
  // НЕ делайте этого. Взятие неконстантной ссылки на shared_ptr не поддерживается и вызывает неопределённое поведение в механизме chaiscript.
}

Совместное использование значений

double &d = chai.eval("var i = 5.2; i"); // d теперь является ссылкой на i в скрипте
std::shared_ptr<double> d = chai.eval("var i = 5.2; i"); // тот же результат, но счётчик ссылок

d = 3;
chai.eval("print(i)"); // выводит 3

Перехват ошибок eval

try {
  chai.eval("2.3 + \"String\"");
} catch (const chaiscript::exception::eval_error &e) {
  std::cout << "Error\n" << e.pretty_print() << '\n';
}

Перехват ошибок, вызванных скриптом

try {
  chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
} catch (const double e) {
} catch (int) {
} catch (float) {
} catch (const std::string &) {
} catch (const std::exception &e) {
  // Это тот, который будет вызываться в конкретном throw() выше
}

Совместное использование функций Двойные кавычки после «to_string» в данном контексте не требуются.

double>>("to_string"); p(5); // calls chaiscript's 'to_string' function, returning std::string("5")


Note: backtick treats operators as normal functions

```cpp
auto p = chai.eval<std::function<int (int, int)>>("`+`"); 
p(5, 6); // calls chaiscript's '+' function, returning 11
auto p = chai.eval<std::function<std::string (int, double)>>("fun(x,y) { to_string(x) + to_string(y); }");
p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++

Language Reference

Variables

var i; // uninitialized variable, can take any value on first assignment;
auto j; // equiv to var

var k = 5; // initialized to 5 (integer)
var l := k; // reference to k
auto &m = k; // reference to k

global g = 5; // creates a global variable. If global already exists, it is not re-added
global g = 2; // global 'g' now equals 2

global g2;
if (g2.is_var_undef()) { g2 = 4; } // only initialize g2 once, if global decl hit more than once

GLOBAL g3; // all upper case version also accepted

Looping

// c-style for loops
for (var i = 0; i < 100; ++i) { print(i); }
// while
while (some_condition()) { /* do something */ }
// ranged for
for (i : [1, 2, 3]) { print(i); }

Each of the loop styles can be broken using the break statement. For example:

while (some_condition()) {
  /* do something */
  if (another_condition()) { break; }
}

Conditionals

if (expression) { }
// C++17-style init-if blocks
// Value of 'statement' is scoped for entire `if` block
if (statement; expression) { }

Switch Statements

var myvalue = 2
switch (myvalue) {
    case (1) {
        print("My Value is 1");
        break;
    }
    case (2) {
        print("My Value is 2");
        break;
    }
    default {
        print("My Value is something else.");
    }
}

Built-in Types

There are a number of built-in types that are part of ChaiScript.

Vectors and Maps

var v = [1,2,3u,4ll,"16", `+`]; // creates vector of heterogenous values
var m = ["a":1, "b":2]; // map of string:value pairs

// Add a value to the vector by value.
v.push_back(123);

// Add an object to the vector by reference.
v.push_back_ref(m);

Numbers

Floating point values default to double type and integers default to int type. All C++ suffixes such as f, ll, u as well as scientific notation are supported

1.0 // double
1.0f // float
1.0l // long double
1 // int
1u // unsigned int
1ul // unsigned long
1ull // unsigned long long

Literals are automatically sized, just as in C++. For example: 10000000000 is > 32bits and the appropriate type is used to hold it on your platform.

Functions

Note that any type of ChaiScript function can be passed freely to C++ and automatically converted into a std::function object.

General

def myfun(x, y) { x + y; } // last statement in body is the return value
def myfun(x, y) { return x + y; } // equiv 

Optionally Typed

def myfun(x, int y) { x + y; } // requires y to be an int

With Guards

def myfun(x, int y) : y > 5 { x - y; } // only called if y > 5

Methods

Methods and functions are mostly equivalent

def string::add(int y) { this + to_string(y); }
def add(string s, int y) { s + to_string(y); } //equiv functionality

// calling new function/method
"a".add(1); // returns a1
add("a", 1); // returns a1, either calling syntax works with either def above

Lambdas

var l = fun(x) { x * 15; }
l(2) // returns 30

var a = 13
var m = fun[a](x) { x * a; } 
m(3); // a was captured (by reference), returns 39

var n = bind(fun(x,y) { x * y; }, _, 10);
n(2); // returns 20 

ChaiScript Defined Types

Define a type called "MyType" with one member value "a" and a getter

Preferred

class MyType {
  var value;
  def MyType() { this.value = "a"; }
  def get_value() { "Value Is: " + this.value; }
};

Alternative

attr MyType::value;
def MyType::MyType() { this.value = "a"; }
def MyType::get_value() { "Value Is: " + this.value; } ### Использование

var m = MyType(); // вызывает конструктор print(m.get_value()); // выводит "Value Is: a" print(get_value(m)); // выводит "Value Is: a"


## Динамические объекты

Все типы, определённые в ChaiScript, и общий Dynamic_Object поддерживают динамические параметры.

var o = Dynamic_Object(); o.f = fun(x) { print(x); } o.f(3); // выводит «3»


Допускается неявное использование this:

var o = Dynamic_Object(); o.x = 3; o.f = fun(y) { print(this.x + y); } o.f(10); // выводит 13


## Пространства имён

Пространства имён в ChaiScript — это динамические объекты с глобальной областью видимости.

namespace("math") // создать новое пространство имён

math.square = fun(x) { x * x } // добавить функцию в пространство имён «math» math.sum_squares = fun(x, y) { math.square(x) + math.square(y) }

print(math.square(4)) // выводит 16 print(math.sum_squares(2, 5)) // выводит 29


### Option Explicit

Если вы хотите отключить определения динамических параметров, вы можете использовать set_explicit.

class My_Class { def My_Class() { this.set_explicit(true); this.x = 2; // это приведёт к ошибке при явном значении true } };


## method_missing

Функция со сигнатурой `method_missing(object, name, param1, param2, param3)` будет вызвана, если соответствующий метод не может быть найден.

def method_missing(int i, string name, Vector v) { print("method_missing(${i}, ${name}), ${v.size()} params"); }

5.bob(1,2,3); // выводит "method_missing(5, bob, 3 params)"


Сигнатура method_missing может содержать два или три параметра. Если сигнатура содержит два параметра, она рассматривается как свойство. Если свойство содержит функцию, дополнительные параметры передаются в содержащуюся функцию.

Если совпадают сигнатуры из двух и трёх параметров, всегда выигрывает функция с тремя параметрами.

## Контекст

 * `__LINE__` Текущий номер строки файла
 * `__FILE__` Полный путь текущего файла
 * `__CLASS__` Имя текущего класса
 * `__FUNC__` Имя текущей функции


# Встроенные функции

## Оценка

eval("4 + 5") // динамически оценивает строку скрипта и возвращает значение последнего оператора eval_file("filename") // оценивает файл и возвращает значение последнего оператора use("filename") // один раз оценивает файл и возвращает значение последнего оператора // если файл уже был «использован», ничего не происходит и возвращается undefined


И use, и eval_file ищут пути usepaths, переданные конструктору ChaiScript.

## JSON

 * from_json преобразует строку JSON в её строго типизированные представления (map, vector, int, double, string)
 * to_json преобразует объект ChaiScript (либо Object, либо одно из map, vector, int, double, string) в его строковое представление JSON

## Дополнительно
ChaiScript сам по себе не предоставляет ссылку на математические функции, определённые в `<cmath>`. Вы можете либо добавить их самостоятельно, либо использовать вспомогательную библиотеку ChaiScript_Extras. (Которая также предоставляет некоторые дополнительные строковые функции.)

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/mirrors-chaiscript.git
git@api.gitlife.ru:oschina-mirror/mirrors-chaiscript.git
oschina-mirror
mirrors-chaiscript
mirrors-chaiscript
develop