Открыть сервис

Embedded Scripting with Squirrel

Squirrel — это легковесный, высокоуровневый, объектно-ориентированный скриптовый язык программирования, предназначенный для встраивания в приложения, написанные на языках C и C++. Язык был разработан Альберто Демичелисом (Alberto Demichelis) в 2003 году. Squirrel сочетает синтаксис, напоминающий C/C++, Java и Python, с динамической типизацией, автоматическим управлением памятью (сборкой мусора) и поддержкой множества парадигм, включая процедурное, объектно-ориентированное и функциональное программирование. Основное назначение Squirrel — предоставление разработчикам возможности реализации гибкой и безопасной логики в игровых движках, графических интерфейсах, сетевых приложениях и других программах, где требуется настройка поведения без перекомпиляции основного кода.

История

Разработка Squirrel началась в 2003 году как проект, призванный создать альтернативу существующим встраиваемым языкам, таким как Lua, Python и JavaScript. Основной целью было создание языка, который бы сочетал простоту встраивания с синтаксисом, привычным для разработчиков на C/C++. Первая публичная версия (1.0) была выпущена в 2004 году. С тех пор язык развивался, получив поддержку множества платформ, включая Windows, Linux, macOS, iOS, Android, а также игровые консоли (PlayStation, Xbox, Nintendo Switch). В 2010 году вышла версия 3.0, которая принесла значительные улучшения в производительности виртуальной машины и расширила возможности рефлексии. Последняя стабильная версия на момент написания статьи — 3.2 (выпущена в 2021 году). Squirrel распространяется под лицензией zlib/libpng, что позволяет свободно использовать его в коммерческих проектах.

Характеристики и особенности

Squirrel обладает рядом ключевых характеристик, определяющих его применение:

  • Встраиваемость: Язык имеет минимальное ядро (около 6-8 тысяч строк кода на C). API для встраивания состоит из набора функций C, позволяющих создавать и управлять виртуальными машинами, загружать скрипты, вызывать функции и обмениваться данными между C/C++ и Squirrel. Сборка мусора работает по алгоритму «mark-and-sweep» (метка-и-очистка).
  • Динамическая типизация: Переменные не имеют фиксированного типа; тип определяется значением во время выполнения. Поддерживаются базовые типы: null, bool, integer (целое 32/64 бита), float (число с плавающей точкой), string (строка), table (ассоциативный массив), array (массив), function (функция), class (класс), instance (экземпляр класса), generator (генератор), thread (сопрограмма), userdata (пользовательские данные C/C++), weakref (слабая ссылка).
  • Синтаксис: Синтаксис Squirrel близок к C/C++ и Java: используются фигурные скобки для блоков кода, точка с запятой как разделитель операторов, ключевые слова if, else, while, for, do, switch, case, break, continue, return, function, class, local, const, static, try, catch, throw. В отличие от C, Squirrel не требует объявления типов переменных.
  • Объектно-ориентированное программирование: Поддерживается прототипное наследование через классы (классы являются объектами первого класса). Классы могут наследовать друг от друга, поддерживаются виртуальные методы, свойства (getters/setters), а также возможность переопределения операторов (_add, _sub, _cmp, _typeof и др.).
  • Функциональное программирование: Функции являются объектами первого класса, их можно передавать как аргументы, возвращать из других функций и сохранять в переменных. Поддерживаются замыкания (closures), анонимные функции (лямбды) и генераторы (функции, которые могут приостанавливать и возобновлять своё выполнение с помощью оператора yield).
  • Сопрограммы (корутины): Squirrel поддерживает легковесные сопрограммы (threads), которые позволяют реализовывать кооперативную многозадачность. Сопрограмма может быть приостановлена с помощью yield и возобновлена из другого контекста.
  • Обработка ошибок: Реализована через механизм исключений с блоками try/catch/throw. Исключения могут быть любого типа данных.
  • Рефлексия: Язык предоставляет возможность во время выполнения получать информацию о типах, классах, функциях, а также динамически создавать и изменять объекты.

Виртуальная машина

Виртуальная машина (VM) Squirrel является стековой. Она компилирует исходный код в байт-код, который затем выполняется интерпретатором. VM поддерживает:

  • Регистры: Внутренние регистры для хранения временных значений и локальных переменных.
  • Стек вызовов: Для управления вызовами функций и возвратами.
  • Стек операндов: Для выполнения арифметических и логических операций.
  • Сборщик мусора: Работает по алгоритму «mark-and-sweep» с инкрементальным режимом, что позволяет снизить паузы при сборке.

Производительность Squirrel оценивается как средняя среди встраиваемых языков: он быстрее, чем чистый Python, но медленнее, чем LuaJIT или JavaScript-движки (V8). Однако для большинства задач в играх и приложениях реального времени его производительность достаточна.

API для встраивания

API Squirrel для C/C++ предоставляет разработчику полный контроль над виртуальной машиной. Основные функции:

  • sq_open() — создание новой виртуальной машины.
  • sq_close() — уничтожение VM.
  • sq_compile() — компиляция исходного кода в байт-код.
  • sq_pushroottable() — помещение корневой таблицы (глобального пространства имён) в стек.
  • sq_call() — вызов функции из скрипта.
  • sq_gettop(), sq_push(), sq_pop() — управление стеком.
  • sq_newclass(), sq_newtable(), sq_newarray() — создание объектов.
  • sq_bindenv() — привязка окружения для выполнения скрипта.

Разработчик может регистрировать собственные функции C/C++ в виртуальной машине, делая их доступными из скриптов. Также поддерживается создание пользовательских типов данных (userdata) с возможностью определения их поведения (конструктор, деструктор, методы).

Применение

Squirrel получил наибольшее распространение в индустрии компьютерных игр. Среди известных проектов, использующих Squirrel:

  • Source Engine (Valve Corporation): Движок, на котором работают игры Half-Life 2, Portal, Team Fortress 2, Left 4 Dead, Counter-Strike: Global Offensive, использует Squirrel для написания логики игровых объектов, сценариев и пользовательского интерфейса (HUD). В частности, в Portal 2 на Squirrel написана большая часть игровой логики.
  • OpenTTD: Открытая реализация транспортной стратегии Transport Tycoon Deluxe. Squirrel используется для написания AI-скриптов (искусственный интеллект для компьютерных соперников) и игровых сценариев.
  • ManiaPlanet (Nadeo): Игровая платформа, включающая игры TrackMania, ShootMania и QuestMania, использует Squirrel для создания пользовательских модов и скриптов.
  • Voxelstein 3D: Игра-шутер, использующая Squirrel для написания игровой логики и поведения врагов.
  • Другие приложения: Squirrel также применяется в некоторых встраиваемых системах, инструментах автоматизации и программах для моделирования.

Пример кода

Пример простой программы на Squirrel, демонстрирующий основные конструкции:

``` // Комментарий local a = 10; local b = 20; local c = a + b; print("Сумма a + b = " + c + "\n");

// Условный оператор if (c > 20) { print("c больше 20\n"); } else { print("c меньше или равно 20\n"); }

// Цикл for (local i = 0; i < 5; i++) { print("Итерация " + i + "\n"); }

// Функция function factorial(n) { if (n <= 1) return 1; return n * factorial(n-1); }

print("Факториал 5 = " + factorial(5) + "\n");

// Класс class Person { constructor(name, age) { this.name = name; this.age = age; } function greet() { return "Привет, меня зовут " + this.name + ", мне " + this.age + " лет."; } }

local p = Person("Иван", 30); print(p.greet() + "\n"); ```

Сравнение с другими встраиваемыми языками

Squirrel часто сравнивают с Lua, Python и JavaScript. Основные отличия:

  • Squirrel vs Lua: Squirrel имеет синтаксис, более похожий на C/C++, что может быть удобнее для разработчиков, привыкших к этим языкам. Lua использует таблицы как единственную структуру данных, тогда как Squirrel предлагает отдельные типы для массивов и таблиц. Squirrel поддерживает классы и наследование «из коробки», в то время как в Lua для этого требуются библиотеки (например, middleclass). Производительность Lua (особенно LuaJIT) часто выше, чем у Squirrel.
  • Squirrel vs Python: Python значительно больше по размеру и сложнее для встраивания. Squirrel имеет меньший размер (около 200 КБ для скомпилированной библиотеки) и более простой API. Python, однако, имеет огромную экосистему библиотек, чего нет у Squirrel.
  • Squirrel vs JavaScript: JavaScript (с движками V8, SpiderMonkey) обычно производительнее, но требует больше ресурсов и сложнее встраивается. Squirrel проще и легче, что делает его предпочтительным для систем с ограниченными ресурсами (например, игровые консоли старшего поколения).

Критика и ограничения

Несмотря на свою популярность в определённых нишах, Squirrel имеет ряд недостатков:

  • Небольшое сообщество: По сравнению с Lua, Python или JavaScript, сообщество Squirrel значительно меньше, что приводит к ограниченному количеству библиотек, документации и сторонних инструментов.
  • Отсутствие стандартной библиотеки: Squirrel не имеет встроенной стандартной библиотеки для работы с файлами, сетью, регулярными выражениями и т.д. Все эти возможности должны быть реализованы разработчиком на C/C++ и зарегистрированы в VM.
  • Производительность: Squirrel уступает по скорости LuaJIT и современным JavaScript-движкам. Для высоконагруженных приложений это может быть критично.
  • Ограниченная поддержка Unicode: Встроенная поддержка Unicode ограничена; строки обрабатываются как последовательности байтов, что может вызывать проблемы при работе с многобайтовыми кодировками.

Интересные факты

  • Название языка «Squirrel» (белка) не имеет официального объяснения, но, по словам создателя, было выбрано из-за ассоциации с лёгкостью и подвижностью.
  • Squirrel используется в движке Source 2 (Valve), который применяется в играх Dota 2, Half-Life: Alyx и Artifact.
  • Язык поддерживает вложенные классы и анонимные классы, что редко встречается в встраиваемых скриптовых языках.
  • Squirrel может быть использован как самостоятельный интерпретатор для написания скриптов, не привязанных к конкретному приложению.

BFOmetr — база данных и аналитика по компаниям России.

На главную BFOmetr →