image

В статье рассказывается про модуль, позволяющий создавать подмножество javascript с любыми ключевыми словами. Строго для безудержного веселья.
На волне статьи про rucckuu.js я обзавидовался и решил обнародовать своё творение: небольшую экосистему для создания произвольных подмножеств javascript. Если к вам давно закрадывалась мысль о том, что некоторые ключевые слова плохо подходят к контексту их применения или мысль о том, что javascript слишком многословен (всякое бывает). Если вы хотите добродушно подшутить над коллегами или просто объяснить вашей маме, чем вы всё-таки занимаетесь на работе, добро пожаловать под кат.


Итак, задача транспиляции сама по себе достаточно проста — найти и заменить. Сама же транспиляция в мире современного фронтенда — неотъемлемая часть интеграции новых технологий и спецификаций: все знают что такое babel или traceur-compiler, да и каждый уважающий себя фронтенд-разработчик время от времени поглядывает в рассылку esdiscuss. Молниеносное развитие нашего стека технологий — это боль и чудо в одном флаконе, потому что от возможностей захватывает дух, а от количества возможных вариаций исполнения у некоторых опускаются руки. Очень повезло тем, у кого они опускаются прямо на любимую или просто попавшуюся под них клавиатуру. Для таких бравых героев эта статья может представлять мало академического интереса, поэтому предостерегаю — всё нижесказанное предназначено только для удовлетворения безудержной страсти к созданию интересных штук. Да.


Вернувшись к транспиляции, задача по замене значений в строке очень тривиальна. Однако задача замены слов, интегрированных с контекстом, уже несколько более интересна. Не затрагивая все тысячи человеко-часов, потраченных на изучение и создание теоретической базы для создания парсеров различных грамматик, перейдём сразу к самому главному. Грамматика языка программирования очень четко определяет контекст использования того или иного ключевого слова, и это использование можно будет трактовать только одним, предопределенным способом. Такой детерминизм следует из самой сути программ, я уверен что нет никого, кто хотел бы видеть два разных результата исполнения одной и той же программы при одинаковых начальных условиях. Исходя из этого — любая программа может быть интерпретирована как весьма определённое синтаксическое дерево. Итак, для языков программирования достаточно просто обуздать синтаксического монстра и получить однозначное определение контекста использования любого слова. Имея на руках контекст, можно делать буквально что угодно.


Я думаю, многие слышали про esprima, парсер ECMAScript. Немного меньше людей знают про jison. Без первого мы бы не увидели jsx так скоро, а второй обязан своему появлению CoffeeScript, оба инструмента достаточно мощные, но esprima специализируется как раз на том, что мы хотим сделать — поменять внешний вид наших программ.


Скупое вступление окончено, к делу.


Создаем MeowScript


  • node, npm по моему предположению не вызывают у вас ужаса
  • npm i your-script в любую удобную директорию
  • заглянем в node_modules/your-script/lexems
  • создадим файл meowscript.lex
  • откроем javascript.lex из той же папки где-нибудь неподалёку
  • в meowscript.lex заменим определения ключевых слов на что-то вроде:

VAR meow
LET meoww
CONST meOw
FOR meowwr
...

  • any-name.js

meowScript = new translator({
    to: 'meowscript'
});

let output = meowScript.parse(`
    var kitty = new Kitty(); if (kitty.isHungry()) {kitty.feed()}
`, {
  from: 'javascript',
  to: 'meowscript'
});

console.log(output);

// stdout:
// meow kitty = MEW Kitty(); meeow (kitty.isHungry()) {kitty.feed()}

В общем, всё.
Область применения модуля ограничена вашим воображением. Под капотом находится как раз esprima, которую я уже упоминал, с тем исключением, что эта версия пропатчена (вручную и с любовью) для того, чтобы поддерживать произвольный набор ключевых слов. Умолчу про объем труда, который пришлось проделать, чтобы вручную найти все hardcoded использования и заменить их на корректные референсы. После этого пришлось лишь добавить загрузчик для поддержки произвольной замены наборов ключевых слов во время исполнения. Работа достаточно простая, но кропотливая.
Помимо этого в комплекте упакован примитивный keyword провайдер с самым примитивным парсером .lex. Все модули валяются в свободном доступе и доступны для пинания всеми желающими



Фактически, с этим набором инструментов можно создавать произвольные подмножества javascript в течении нескольких минут. Единственное ограничение — неспособность модуля находить стандартные интерфейсы ноды или браузера. Так что увы, document.body.getBoundingClientRect, господа. Добавить поддержку транспиляции интерфесов тоже не так сложно, нужно всего лишь определить правила следования identifiers и осуществлять замену согласно им.


Напоследок, картинка в хедере поста неслучайна, как пример использвания your-script, я написал redscript — русское подмножество javascript. Ну и как следствие использования настоящего парсера:


var стр = 'var';

будет корректно транспилировано в:


пусть стр = 'var';

Сам модуль валяется в npm. Для затравки, пример транспилированной программы:


функция функ(икс, игрек, зет) {                         
    примем и = 0;                              
    примем икс = {0: "ноль", 1: "один"};          
    примем функ = функция () {                  
    }                                          
    если (!и > 10) {                           
        для (примем джей = 0; джей < 10; джей++) {      
            переключатель (j) {                
                положение 0:                   
                    значение = "zero";            
                    стоп;                      
                положение 1:                   
                    значение = "one";             
                    стоп;                      
            }                                  
            примем с = джей > 5 ? "БЧ 5" : "МР 5";
        }                                      
    } иначе {                                  
        примем джей = 0;                          
        попробуй {                             
            пока (джей < 10) {                    
                если (и == джей || джей > 5) {       
                    a[джей] = и + джей * 12;         
                }                              
                и = (джей << 2) & 4;              
                джей++;                           
            }                                  
            делай {                            
                джей--;                           
            } пока (джей > 0)                     
        } лови (e) {                           
            alert("Крах: " + e.message);    
        } затем {                              
            обнулить(a, и);                       
        }                                      
    }                                          
}              

В целях рекламы, это пока единственный модуль, который позволяет вам сделать


лови (крах) {
  КрахДетектор(крах);
}

В целом, придумывать альтернативы ключевым словам безумно интересно. Если придумаете что-то крутое — оставьте, пожалуйста, в комментариях. Всем хороших выходных и много-много, бесконечно много удовольствия от того, что вы делаете :)

Поделиться с друзьями
-->

Комментарии (42)


  1. a553
    07.05.2016 13:17
    +12

    если (!и > 10)
    А вот и первый баг.
    alert("Крах: " + e.message)
    Надо было так:
    внимание_внимание("Крах: " + e.говорит_москва)


    1. Everlier
      07.05.2016 13:30
      +17

      Прошу запрос на втягивание, если вы понимаете, о чем я:)


      1. a553
        07.05.2016 14:03
        +4

        На баг — отправил, втягивайте.


        1. i360u
          08.05.2016 08:59
          +3

          жук же!


          1. a553
            08.05.2016 09:00
            +1

            Действительно, как же я так опростоволосился.


  1. ExplosiveZ
    07.05.2016 13:22
    +9

    А что за шрифт на картинке?


    1. Everlier
      07.05.2016 13:31
      +4

      Простите за минус, поднял вам карму.
      Шрифт — нарисовал в иллюстраторе :)


    1. Everlier
      07.05.2016 13:37
      +4

      Извините, не смогу поднять, у вас нет публикаций. Минус поставил ошибочно, еду в переполненной электричке. Лето начинается :)


  1. Per_Ardua
    07.05.2016 13:32
    +3

    Хах, прикольная штука!
    Продолжая последний пример:

    испытатьВесьЭтотКод {
    самВыбрасываюОшибку «Ошибка!»;
    }


    1. Everlier
      07.05.2016 13:41
      +1

      Вы можете сделать это очень просто, можно отредактировать redscript.lex который в комплекте с модулем rscript, ссылка есть в посте.


  1. lenar
    07.05.2016 15:13
    +7

    Это для 1С-ников? :)


  1. Goodkat
    07.05.2016 15:42
    +8

    Читерство. Я вот в детстве хекс-едитором турбопаскаль русифицировал.


  1. serafims
    07.05.2016 16:37
    +2

    Вообще читабельность чуть выше стала, с применением «примем икс=0» и «значение=7»…


  1. YChebotaev
    07.05.2016 22:27
    +7

    А ведь англоговорящие именно так и воспринимают текст программ на своем родном языке.


    1. Everlier
      08.05.2016 19:32

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


      1. mpakep
        09.05.2016 21:29

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


      1. mpakep
        09.05.2016 21:41

        Прямо волна руссификации языков. К сожалению стандарты отстают. Есть вероятность что разные реализации будут продвигать разные имена одних и тех же конструкций. Хорошо бы задуматься о стандартизации синтаксиса. Хорошо, что наконец то маятник качнулся от стадии необоснованного отрицания к сдержанному одобрению. Мне всегда подобных вещей не хватало. В душе завидовал 1с никам где проще к подобным вещам относятся и не парятся предоставив наравне с русским и английским грузинский, украинский и многие другие. Ждем следующую статью с наброском стандарта руссификации языка.


  1. shurochkin
    08.05.2016 00:13

    А вы где такой стафф берете?


    1. Everlier
      08.05.2016 19:30
      +1

      Из мозга прилетает, зачастую


  1. Alesh
    08.05.2016 01:22
    -9

    Предлагаю не «КрахДетектор», а «ТрахДетектор» :)


  1. 4ertovo4ka
    08.05.2016 10:39
    +1

    Спасибо огромное за пост!
    Смеялась от души.

    Вспомнилась школа и уроки, где нас учили основам программирования примерно вот так же :)


  1. Demogor
    08.05.2016 11:38

    Знатно!
    Отличная интерпретация старой шутки:
    #объявить правду ложью //счастливой отладки, с*ки


  1. Demogor
    08.05.2016 11:47

    Кстати, а есть ли возможность переопределения операторов?


    1. Everlier
      08.05.2016 21:32
      +1

      Для этого нужно будет поправить модуль, сделать селектор замены более абстрактным, дописав фабрику матчеров для ветвей AST. Отвечая на ваш вопрос — пока нет, но сделать можно. Сложность будет еще и в том, что придётся сделать референсы на все операторы в esprima.


  1. extempl
    08.05.2016 14:04

    Что-то у вас там с переменной джей напутано в примере, и а непонятно откуда взялась.


  1. nikis05
    08.05.2016 21:32

    пусть обещание = новый Обещание(функция(исполнить, отклонить) {
    установитьВыходВремени(функция() {
    испонить('окей');
    }, 4000);
    }


  1. DDroll
    08.05.2016 21:32

    Вообще, на ванили писать — это для небольших приложений. Для крупных лучше использовать каркасы вроде Хребет.js или хотя бы библиотеки вроде жЗапрос.


    1. Everlier
      08.05.2016 21:35
      +1

      Ну или использовать уже устоявшийся стек — угловат.джс или воздействие.джс. К сожалению если вы хотите истинной изоморфности, придётся учитывать квирки узла.джс :)


  1. LifeKILLED
    08.05.2016 21:35

    Я всегда знал, что жизнь вэб-программиста тяжела и мучительна, но чтоб довести человека до такого безумия?!.. Пожалуйста, отсыпьте мне модулей, которые вы прикуривали перед тем, как словить такой эпичный приход XD

    Ключевые слова «иначе» и «пусть» — это гениально, как и вся программа… А может, построим-таки коммунизм с нашими, родимыми, драгоценными советскими Ц++ и КофейныйСценарием? :D


    1. Everlier
      08.05.2016 22:31

      Все вышеописанное достаточно тривиально, это один из сотен (тысяч?) подобных проектов, я не думаю что стоит относиться к этому с таким сильным воодушевлением, давайте лучше придумаем что-нибудь интересное :)


      1. LifeKILLED
        11.05.2016 18:11

        Идея такая: перевести Яву на китайские иероглифы, вот будет весело :D


  1. AndreyRubankov
    08.05.2016 22:31

    забавно и даже лучше, чем у коллеги из недавних постов)
    но всегда, когда вижу такую русификацию вспоминается увиденный код в 1С: новый НТТРЗапрос() // ЭнТэТэЭр Запрос =)

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


    1. Everlier
      08.05.2016 22:35
      +1

      Англоязычность программирования — факт, но нам совершенно необязательно мыслить исключительно в этой категории.
      По счастью я не имею ничего общего с 1С, но вот делать запросы по протоколу передачи гипертекста (ППГТЗапрос :) ) приходится постоянно. Представляю себе профит от сиюжесекундного понимания контекста просто из того, что программа написана на твоём родном языке.


      1. AndreyRubankov
        08.05.2016 23:08

        Меня 1С, к счастью, тоже обошел стороной, но как знакомые на нем пишут видел, — читать базовые конструкции языка, не так тяжело (но с непривычки — не приятно), а вот бизнес логику воспринимать еще тяжелее. Вместо привычных репозиториев и DAO и прочего — там регистры, словари и прочее, но это уже больше DSL.

        А для размышления, могу предложить идею, которой когда-то на первом курсе в университете баловался на С/С++ через макросы:

        Даны целые А = 5, Б = 6. Вывести минимум от (А, Б). Вывести сумму (А, Б).

        можно ради удовольствия попробовать развить эту идею =)


  1. wikipro
    08.05.2016 22:35

    Жаль что никто не говорит, что на практике очень удобно использовать русские названия для разделения пространств имён и разделения своих переменных и чужих. Я например это использую в Питоне.


    1. Everlier
      08.05.2016 22:35

      Очень и очень спорный вопрос.


  1. BkmzSpb
    08.05.2016 22:37

    Если последний пример — это транспилированная программа, почему в первом if в цикле объявляется переменная 'j', а чуть ниже используется уже 'джей'? Я так понимаю, 'джей' должно быть везде?

    И еще один момент — но это уже чисто с позиции «полной русификации» — почему бы не заменить строки 'ГТ' и 'ЛЕ' на совсем уж русские 'БЧ' и 'МР'?))

    А в целом — очень интересный опыт, для русскоязычного программиста ( не 1С) — новый взгляд на код)


    1. Everlier
      08.05.2016 22:37

      Вы правы, поправил :)


  1. parmactep
    08.05.2016 22:38

    «Здесь русский дух, здесь 1С пахнет.»


    1. Nefilim_312
      10.05.2016 13:02
      +1

      «OdinAss»


  1. SkyHunter
    12.05.2016 21:37

    Всё-таки допилить до синтаксиса 1С — и можно будет шабашить прямо на работе, никто ни о чём не догадается.


  1. Zmeiugo
    13.05.2016 06:20

    Надо ж, куда импортозамещение добралось О_о…