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 →


