Emoji Lisp

в 3:58, , рубрики: emoji, peg, ненормальное программирование, функциональное программирование

(пятница)
Всё началось с того, что я прочитал у Станислава Лема в романе «Мир на Земле» (1985), что в будущем общение на языке будет заменено общением при помощи пиктограмм. Мне показалось это довольно пророческим в связи с возрастающим интересом к различным смайликам и другим видам более крупных картинок и я подумал: а что если программировать при помощи emoji? Поискав в сети я убедился, что мысль такая уже приходила в головы людей и воплотилась в проект https://github.com/wheresaddie/Emojinal
но этот проект меня не впечатлил, во-первых язык не обладает полнотой и вообще подход автора как попытка заменить часть операторов при помощи emoji показалась не сильно интересной.

Я подумал, что Лисп гораздо лучше будет ложиться на emoji, потому что закрывающие-открывающие скобки это уже будто смайлики, плюс ко всему, сам язык очень прост, компилятор можно написать довольно быстро и для того чтобы всё «работало» не требуется реализации большого количества разных конструкций.

Так как хотелось предоставить пользователям возможность легко попробовать этот новый язык, было решено сделать его встраиваемым в браузер. В качестве языка компилятора можно было выбрать любой язык, который компилируется в JavaScript, но я выбрал просто JavaScript и решил написать так, чтобы это можно было компилировать как в окружении node.js, так и в браузере. Второй момент, которого мне бы хотелось достичь это изменяемость набора emoji, я уже с первых операций начал сомневаться в том, что выбор emoji-представления действительно однозначен и решил сделать всё так, чтобы другому разработчику было просто заменить этот набор символов и посмотреть какими получаются новые emoji-программы. По этой причине все примеры с тестами записываются в виде шаблонов, в которые подставляется текущий набор.

В качестве языка для описания грамматики я выбрал PEG, единственная проблема с ним была в том, что unicode-символы не получалось сделать перечислением в условиях (пришлось отдельно перебирать первый и второй символ, потому что для него это несколько символов). Плюс возникла сложность связанная с перекомпиляцией PEG-парсера, поскольку приходилось бы каждый раз менять определение идентификаторов (выкусывая скобки) и пересобирать парсер при помощи PEG.js, что мне показалось достаточно медленным на стороне браузера. Было принято довольно простое решение — перед подачей программы на лексический анализ заменять текущие символы скобок из набора на обычные скобки, а потом уже парсить с обычными скобками. Получился такой PEG:

start
  = s:sexpr* {return {type:"Program", body:s}}

leftBracket
  = "("

rightBracket
  = ")"

identifier
  = [uD83D][uDC36-uDE4F]
  / [uD83D][uDE80-uDEC5]
  / [uFE0F]
  / [u2702-u27B0]
  / [u24C2]
  / [uD83C][uDC04-uDFE2]
  / [u20E3-u3299]

number
  = [0-9]+

_ "whitespace"
  = [tvf nu00A0uFEFF]*

sexpr
  = a:atom { return a; }
  / list

list
  = leftBracket _ head:sexpr
    tail:(_ sexpr)* _ rightBracket _ {
      var result = [head];
      for (var i = 0; i < tail.length; i++) {
        result.push(tail[i][1]);
      }
      return {type: 'List', contents:result};
    }

atom
  = d:number _ { return {type: 'Literal', value: parseInt(d.join(""), 10)}}
  / '"' d:(!'"' [a-z])* '"' _ { return {type: 'Literal', value: d }}
  / s:identifier _ { return {type: 'Identifier', name: s.join?s.join(""):s}}

Дальше-проще: я выбрал набор функций, которые вошли в простенькую стандартную библиотеку, это:
Emoji Lisp
и для того чтобы продемонстрировать их работу написал вычисление чисел Фибоначчи, вычисление самой себя и ещё несколько простых программок
кроме того, экспоритровал картинки и коды из проекта gemoji для более наглядной демонстрации.

Так выглядит программа, вычисляющая саму себя:
Emoji Lisp
здесь месяцы — скобки, животные — идентификаторы, остальные конструкции есть выше.

Так выглядит программа для чисел Фибоначчи:
Emoji Lisp
это рекурсивная функция имя которой — собачка. Эмоджи символы можно писать подряд, но цифры идущие подряд нужно разделять пробелами, если они относятся к различным числами.

В первой версии вместо месяцев использовались грустные-весёлые смайлики, но из-за их похожести код гораздо сложней было структурировать, по этой причине перешёл на месяцы. Правда, мне не совсем понятно зачем в стандартном наборе emoji есть месяцы, смотрящие в разные стороны.

В процессе выяснил, что emoji не так уж хорошо поддерживаются, к примеру, sublime позволяет копировать только некоторые из них, если попытаться скопировать текст программы вычисляющей саму себя он как бы скопирует, но в буфере обмена будет пусто. Из десктопных браузеров более-менее нормально emoji поддерживаются Safari. Компиляор поддерживает emoji в виде unicode-символов и есть даже repl но писать терминал тоже не слишком хорошо поддерживает такие символы, они наступают друг на друга, но надеюсь что в будущем ситуация улучшится и мы сможем спокойно писать вызовы эмоджи-утилит прямо в командной строке.

Все исходники доступны на https://github.com/parsifal-47/emojilisp, там можно расширить стандартную библиотеку или написать запрос на это, кроме того, можно попробовать свои силы в программировании на этом простом наборе функций по адресу emojilisp.com. И как я писал в самом начале, мне хотелось, чтобы можно было так же переопределять набор emoji соответствующих функциям без особого труда. Это можно сделать поменяв файлы в папке conf проекта на github или нажав кнопку «create your own set» на сайте, после чего сетом, как и любой программой можно поделиться. Вот, к примеру, вариант с более интересным символом для операции list.

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

Автор: parsifal

Источник

* - обязательные к заполнению поля