Еще один язык, транслируемый в JavaScript — ColaScript


    Всем привет! В этой статье я хочу вам представить свой язык — ColaScript. В двух словах это язык с новым синтаксисом, транслируемый в JavaScript. Начну я с того, что расскажу о причинах появления этого языка.

    Причины появления



    Зачем вообще нужны транслируемые в JavaScript языки?

    Лично для меня польза в использовании таких языков это, конечно же, в первую очередь, синтаксический сахар, позволяющий сокращать количество кода. Во-вторых, это структурность ( ООП, модули, пакеты… ), которую не так просто достичь на чистом JavaScript. На данный момент существуют 3 языка, обладающие почти всеми перечисленным качествами:

    CoffeeScript

    Это самый первый язык такого типа, о котором я узнал. На настоящий момент в этом языке существует большое количесвто синтаксических фишек и присутствует ООП в лице классов. Общий стиль синтаксиса в CoffeeScript'а такой же, как в Ruby и Python'е, это выглядит классно, но лично мне хотелось видеть все те же фишки, но с C-подобным синтаксисом. Также в CoffeeScript отсутствует подключение исходников/модулей из кода.

    TypeScript

    TypeScript — язык, разрабатываемый компанией Microsoft, имеющий статическую типизацию, реализацию ООП и подключение модулей. В плане структурности все отлично, но в нем нету сахарного синтаксиса.



    Dart

    Мое первое знакомство с этим языком состоялось вскоре после появления его первой версии: язык был еще сырой, да и я сам тогда еще не очень понимал, зачем он такой нужен. Летом прошлого года я решил посмотреть что же стало с этим языком — это было то что надо: ООП, пакеты ( даже со своим менеджером ), хорошая стандартная библиотека и синтаксический сахар, из которого мне особенно запал в душу каскадный оператор:

    query("#myElement")
        ..innerHtml = "Hello World!"
        ..style.backgroundColor = "red";
    

    Dart язык хоть и компилируемый в JavaScript, но без обратной с ним совместимости. В частности, это приводит к большому весу рантайма и библиотек, а также к сложностям в работе с уже существующим JavaScript кодом.

    В итоге

    В итоге мной овладело желание создать свой язык, который заимствует лучшие стороны трех вышеперечисленных языков. Так был придуман ColaScript.

    Немного о процессе создания


    За основу был взят такой инструмент, как UglifyJS. UglifyJS создан для сжатия JavaScript кода, для этого он парсит код и работает с AST деревом. Моей задачей была модификация парсера под новый синтаксис, а так же непосредственно написание транслятора ColaScript-AST в JavaScript-AST, все остальное в UglifyJS уже есть. Парсер был усовершенствован для поддержки как ColaScript, так и JavaScript одновременно, это сделано для того, что бы вы могли без проблем подключать библиотеки и фреймворки написанные на JavaScript.

    Что получилось


    Результат моей работы вы можете посмотреть на github'е, поиграться с языком вживую вы можете тут. На данный момент закончен только первый этап разработки и язык пока что не имеет особых преимуществ перед теми же CoffeeScript, TypeScript и Dart, но есть еще много идей для реализации, которые описаны здесь.

    Совсем небольшой пример кода:
    @use strict
    
    main(){
        console.log("
    
            Hello World!
            This is simple example for Habrahabr.ru!
            
            P.S. I love haters so much :-)
            @{Date()}
    
    
            ");
    }
    

    Результат перевода:
    "use strict";
    
    window.addEventListener("DOMContentLoaded", function main() {
        console.log("\nHello World!\nThis is simple example for Habrahabr.ru!\n\nP.S. I love haters so much :-)\n" + Date() + "\n\n");
    }, false);
    

    Жду ваши мнения об языке. Всем спасибо за внимание.
    Поделиться публикацией

    Похожие публикации

    Комментарии 55

      +14
      Зачем?
        –1
        Все написано в статье.
          +22
          просто у человека, скорее всего первым ЯП был C, и он нанес тяжелейшую психическую травму.
            0
            Ой, зря вы так. Классика же.
          +30
          Coffeescript+Colascript и спать не будете. Совсем.
            +25
            Надо MentosScript запилить) Но с asm-подобным синтаксисом, вот это будет МООЩЬ!
              +1
              Тогда ко всему этому еще надо VodkaScript.
              0
              Вы уж простите, но мне не понравилось. После прочтения Overview сложолось впечатление, что понабирали фишек из CoffeeScript, разбавили типизацией, убрали удобочитаемый синтаксис с отступами и вот вам. Ни коем образом не умаляя проделанной работы, считаю что популярность ColaScript в таком виде не обретёт.

              P.S.
              Вы знакомы с ClojureScript? Идеология у него полностью отлична от CoffeeScript, что совсем не мешает ему расти и развиваться.
                +9
                В статье про сам язык ничего не написано.
                Опциональная типизация — штука хорошая, но подобная, которая не выдает ошибку даже в момент компиляции, к черту ни сдалась:

                String str = {}; // => var str = {};
                

                Языка как такового еще нет. Даже сахар для классов (из-за отсутствия которого большинство и берут язык, компилируемый в js) только в планах.
                Все примитивно и громоздко. Посмотрите, например, LiveScript, пропустив примеры (могут отпугнуть) и сразу перейдя к сахару.
                  +16
                  image

                  Я наоборот так реагирую на компилируемые в JS языки.
                    0
                    Расскажите, пожалуйста, о результатах работы — что кроме, понятное дело, удовольствия от создания использования собственного языка это дало?
                    Какие моменты разработки ускорило? Упростило совместную работу или чтение кода? Что-то конкретное, что могло бы замотивировать попробовать язык. Возможно у вас есть проект с успешно внедренным ColaScript или это просто академическая наработка? Вы один разрабатываете и какие планы на поддержку и развитие — сколько времени вы готовы уделять и на что живете при этом?
                    Вы пишите, «not always valid-javascript is valid-colascript». Как быть с другими библиотеками?

                    По поводу языка:
                    1. Название не понравилось — слишком похоже на Coffee + еще и реклама сомнительного напитка.
                    2. Во Future не понравилось «HTML and CSS stuff». ИМХО, разрыв мозга при чтении кода, строку читать без разделителя еще и с переносами строк. Однако в строке multiline неплохо.
                    3.isset clone порадовали, однако это решено практически в любом фреймворке.
                    4. Большое количество для возможного создания именованной функции не понравилось — читать код очень неудобно.

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

                      Один, все что сейчас есть написано за месяц, темп сбавлять не планирую. Я студент, подрабатываю фрилансом — сайты верстаю.
                      Вы пишите, «not always valid-javascript is valid-colascript». Как быть с другими библиотеками?

                      Этим я хотел сказать что компилировать js как cs не стоит, подключать без проблем можно любой js код: @require "jquery.js" — компилятор определяет по расширению файла как ему следует парсить исходинк.
                      2. Во Future не понравилось «HTML and CSS stuff». ИМХО, разрыв мозга при чтении кода, строку читать без разделителя еще и с переносами строк. Однако в строке multiline неплохо.

                      ReactJS'ом вроде люди пользуются, смотря на это решил позаимствовать и это.
                      +12
                      boolean aliases: True/False = on/no
                      o_O
                        0
                        Тогда уж лучше, как в Objective-C: YES/NO
                          +1
                          вырвали из контекста просто, вот все алисасы:
                          true == yes == on
                          false == no == off
                        +1
                        Обзор фич на Github очень скомканный. Местами непонятно, как пользоваться предложенным синтаксисом. Местами непонятно, что получится в результате. И непонятно, какие фичи есть в других языках, а какие уникальны.

                        Сделайте, пожалуйста, сравнительную таблицу синтаксисов и фич.
                          –1
                          Местами непонятно, как пользоваться предложенным синтаксисом.

                          Подскажите какими местами и я постараюсь поправить.
                          Местами непонятно, что получится в результате. И непонятно, какие фичи есть в других языках, а какие уникальны.

                          Хорошо, приведу пример перевода и подпишу что и от куда взято.
                          +1
                          А LiveScript видели? Очень богатый на фичи язык, и сами фичи очень интересные.
                            +2
                            CoffeeScript мне не нравится — там того пресловутого сахара столько, что в заднице слипается.
                            Мне кажется, что максимальная краткость != наилучшая читаемость. И что если полностью отказаться от слов в языке, в глазах будет рябить от спецсимволов. Сахар должен быть в меру.

                            У вас вроде бы не так радикально.
                            Но… нет ощущения целостности и единства стиля. Возможно, по причине не слишком аккуратной доки.

                            P.S. Кстати, а кто рисовал логотип? Неплохой леттеринг.
                              0
                              там того пресловутого сахара столько, что в заднице слипается.

                              Вы, наверное, с Ruby не работали.

                              Прелесть coffeescript'а в том, что он даёт вам возможность использовать сахар, но не заставляет это делать. Для того, чтоб его адекватно воспринимать, нужно на нём писать хотя бы с месяц.
                                0
                                Ну проблема CoffeeScript не в том, что слишком уж сложно читается (хотя да, сложнее, чем чистый JS, несмотря на меньшее количество кода).
                                Я отказался в итоге от любимого Coffee из за недостаточной популярности — люди хотят видеть JS, иметь возможность его менять, читать, и так далее. То же касается большинства языков, компилируемых в JS. Не, у CoffeeScript достаточно сторонников, но все же очень многие его не очень жалуют.
                                  –2
                                  Как это не заставляет? Там разве можно вмеcто дурацкой (дурацкой потому, что она нормально не видна и в глазах рябит от спецсимволов) стрелочки написать нормальное слово function?
                                    0
                                    Ну понятно дело, что не всё. Объявление функций, точки с запятыми и ещё некоторые основные отличия — неизменяемы. Однако там туева куча опциональных знаков и подходов.
                                  0
                                  P.S. Кстати, а кто рисовал логотип? Неплохой леттеринг.

                                  Это шрифт Dancing Script
                                    +1
                                    Согласен с вами, писал на vanilla js, потом перешел на coffeescript, а потом опять вернулся к native. Просто только с опытом приходит осознание самого языка: чем он является, а чем нет. Я думаю нет смысла переубеждать автора в том, правильно ли писать на препроцессорах к js или нет, тут каждый находит свою истину.

                                    Но свои пять копеек я всё же внесу: кофе хорош, но только на каких-то простых или маленьких проектах, над которыми вы работаете один или в небольшой команде. Когда проект содержит сложную логику, на кофе становится тяжелее писать. Тем более мне нравится стандартизирванный код, а опциональность вроде do или () порой смущает. Когда большая команда разработчиков пишет на coffee, все в результате пишут по-разному, и никакие coffeelint тут не помогают(конечно, можно развести из этого холивар, но я не преследую такую цель, это просто моё мнение).
                                  0
                                  Расписал какие-то моменты.
                                  1) Зачем нужен этот каскадный оператор, каскады с одной точкой вместо двух работают из коробки и так.
                                  2) Удорожание вызова функций.
                                  3) ` — но зачем? Может лучше «» тогда поддержать?
                                  4) multiline — вот это прекрасно. align goes by closing-quote, а вот это — нет.
                                  5) Реквестирую фичу arr[-1] (предпоследний элемент)
                                  6) isset творит чёрте что. Если переменная задана как null, то она нот сеттед. Реальный нот сеттед будет скорее — try{ var b = a;}catch(e){ // Not setted }
                                  7) ** — паскальный синтаксис, может стоит добавить ещё и ^?
                                  8) Каскадный каскадный оператор чудесен, но синтаксис дик. По сути хотелось бы обычную разновидность apply(extjs)\extend(jquery) с каким-то переходом вверх.

                                  Как уже заметили выше — если типизация есть, то её надо использовать. Для выявления ошибок на уровне компиляции, для некоторой оптимизации функций под конкретные типы.
                                    +2
                                    1. С одной точкой цепочки работают только если метод возвращает this. Каскадному оператору на то, что возвращает метод, наплевать.
                                    5. Предпоследний? А последний тогда как? :) В Coco / LS — array[*-1]
                                    6. Полностью согласен, заметил сразу, но из-за такой мелочи комментарий писать было лень. У кофеподобных языков с этим всё замечательно.
                                    7. Тык.

                                    Трэша хватает: чего только стоят эти строчки из clone:

                                    var result, types = [ Number, String, Boolean ];
                                    for (var i in types) if (types.hasOwnProperty(i) && _item instanceof types[i]) return types[i](_item);
                                    if (_item.__proto__ === Array.prototype) {
                                      result = [];
                                      _item.forEach(function(child, index, array) {
                                        result[index] = $_cola_clone(child);
                                      });
                                      return result;
                                    }
                                    

                                    Поясню:

                                    > for-in + hasOwnProperty для обхода массива.
                                    > Объекты Number, String, Boolean клонируются в примитивы, на примитивы instanceof не работает, они идут дальше.
                                    > Клоном объекта new Boolean(false) будет примитив true.
                                    > Проверка, является ли объект массивом — через сравнение нестандартного свойства __proto__ с прототипом массива — до свидания, IE10-.
                                    > Обход массива теперь уже через forEach — до свидания, IE8- (хотя да, с ними мы уже попрощались). Обычные циклы нонче не популярны.

                                    В общем, весело там.
                                      0
                                      Я не разгромить язык пытался, а высказал мыслей.
                                      1. Но что-то адовое есть с двумя точками (кстати, обработан ли кейс у чисел? Сейчас в js оно понятно почему, но wat делает вот так: 2..toString() = (2).toString
                                      5. А последний — arr[], если уж такой синтаксис. Но логичнее -1 ~ синоним [], -2 — предпоследний.

                                      forEach — надо расширять прототип Array — это один из случаев когда расширение — благо.
                                      Собственно избежать трэш можно если генерировать функции клонирования, основываясь на введённой типизации (попутно можно неплохо поддержать asm.js).
                                        0
                                        Так и я по началу ничего громить не собирался, но как код посмотрел… На несколько комментариев решил не разносить.
                                        Добавление forEach — да, благо, сам кой что глобальное, что прототипы встроенных конструкторов расширяет, релизить собираюсь. Только этот метод здесь никто и не добавляет, не к месту он, да и мелочь это по сравнению с остальным.
                                          0
                                          Чёрт, я ночью спутал с автором.
                                          0
                                          по поводу индексов массива все верно…
                                          хорошо, если будут работать дополнения(хотя там в любом случае надо чтоб выражения работали):
                                          arr[~0] === arr[-1]: последний
                                          arr[~1] === arr[-2]: предпоследний
                                          –1
                                          Оператор clone добавлял стиснув зубы, так как код самой функции это по сути костыль, но иногда такой оператор действительно пригождается.
                                          Предлагайсте свою реализацию этой функции )
                                            0
                                            Свою реализацию? Да без проблем. Примерно так, код особо не проверял.
                                            Простое глубокое клонирование структур Array и Object, с учетом прототипа. А в рамках языка большего и не нужно (хотя раньше думал иначе).
                                            Треть — костыли для ES5. Треть — стек для корректного клонирования структур типа var a={}, b={}; a.b=b; b.a=a;.
                                            Скрытый текст
                                            function indexOf(arr, val){
                                              var $indexOf = Array.prototype.indexOf;
                                              if($indexOf)return $indexOf.call(arr, val);
                                              for(var i = 0, l = arr.length; l > i; i++)if(arr[i] === val)return i;
                                              return -1;
                                            }
                                            var getProto = Object.getPrototypeOf || function(it){
                                              return it.__proto__ || (it.constructor && it.constructor.prototype) || Object.prototype;
                                            }
                                            var create = Object.create || function(proto){
                                              var C = function(){};
                                              C.prototype = proto;
                                              return new C;
                                            }
                                            function clone(it, stack1, stack2){
                                              if(it == null || typeof it != 'object')return it;
                                              stack1 = stack1 || [];
                                              stack2 = stack2 || [];
                                              var index = indexOf(stack1, it);
                                              if(~index)return stack2[index];
                                              switch(Object.prototype.toString.call(it).slice(8, -1)){
                                                case 'Array':
                                                  var result = [];
                                                  stack1.push(it);
                                                  stack2.push(result);
                                                  for(var i = 0, l = it.length; l > i;)result.push(clone(it[i++], stack1, stack2));
                                                  return result;
                                                case 'Object':
                                                  var result = create(getProto(it));
                                                  stack1.push(it);
                                                  stack2.push(result);
                                                  for(var key in it)if(Object.prototype.hasOwnProperty.call(it, key)){
                                                    result[key] = clone(it[key], stack1, stack2);
                                                  }
                                                  return result;
                                              }
                                              return it;
                                            }
                                            

                                          –1
                                          5) подумаю над этим
                                          6) isset тварит ровно то что и? в кофе
                                          7) ^ — такой оператор есть в JavaScript

                                          на счет типизиации — наверное я не так выразился на англисков в овервью, но пока типизация это просто синтаксис. Оживлять ее, делать статической — это первое чем я сейчас займусь.
                                            +1
                                            6. Всё просто. В кофе код проверки инлайнится в код, у вас используется хэлпер. Но тут проблема — необъявленную переменную нельзя использовать нигде, кроме typeof, а у вас она передается в функцию. В итоге:

                                            foo?       // => false - кофе
                                            isset foo; // => Uncaught ReferenceError: foo is not defined - кола
                                            
                                              0
                                              Спасибо за разъяснение, подправлю.
                                          +1
                                          Мое единственное замечание — не делайте вы эти алиасы и возможность написать одно и тоже миллионами способами, пусть все пишут одинаково, ну что за бардак =( хочешь пиши function, хочешь void, мало 2х видов кавычек, пожалуйста — вот тебе третьи.
                                            –1
                                            На самом деле, третий вид кавычек может быть удобным, если в строке активно используются как одинарные, так и двойные кавычки. При возвращении строки в HTML такая ситуация возможна легко. Обратные кавычки тут будут очень удобными.
                                              0
                                              Не нужно смешивать html код с обычным кодом, для меня это не очень приемлемо, в крайних случаях есть экранирование, а в html можно использовать и одинарные и двойные кавычки.
                                                0
                                                Тут в язык встроена подстановка переменных в строки. Наверное, не просто так :) Иногда бывает удобно. Хорошо, когда язык предлагает много разных инструментов на все случаи жизни. Насчёт алиасов true/false согласен, это лишнее. А вот с кавычками фишка мне нравится.
                                            +1
                                            Было бы круто увидеть прямо в статье несколько хэлоуворлдов. Для наглядности.
                                              0
                                              поиграться с языком вживую вы можете тут

                                              Комментарии в скомпилированном коде нужно было оставить для сравнения. Сейчас там мало что можно быстро и без подсветки найти.
                                                –1
                                                К сожалению в UglifyJS нету возможности сохранять комментарии.
                                                  0
                                                  UglifyJS
                                                  --comments
                                                  Preserve copyright comments in the output. By default this
                                                  works like Google Closure, keeping JSDoc-style comments
                                                  that contain "@license" or "@preserve". You can optionally
                                                  pass one of the following arguments to this flag:
                                                  — «all» to keep all comments
                                                  — a valid JS regexp (needs to start with a slash) to keep
                                                  only comments that match.
                                                  Note that currently not *all* comments can be kept when
                                                  compression is on, because of dead code removal or
                                                  cascading statements into sequences.


                                                  Вы используете иной UglifyJS?
                                                    +1
                                                    Извините, прочел невнимательно. Теперь в playground'е комментарии сохраняются.
                                                +3
                                                но в нем нету сахарного синтаксиса


                                                Честно говоря, меня пугают программисты, которые ставят во главу угла синтаксический сахар. Создавать язык только ради сахара — весьма странная затея. Язык должен помогать решать крупные проблемы программиста, а не помогать писать красивые однострочники.
                                                  0
                                                  Это компилируемый в жс язык. Сахар можно поставить во главу когда понимаешь что вот уже тысячу раз писал получение предпоследнего элемента кодом вида arr[arr.length — 2], а язык позволяет написать arr[-2]. Но я пока не уверен конкретно в этом языке, пока ни один из таких языков не перевесил. Closure разве что я пока не внимательно вчитывался. На одной чаше весов оказывается дебаггинг, встраивание препроцессора в стек разработки, уменьшение скорости работы кода, на другой — скорость разработки.
                                                    0
                                                    Это понятно. Но непонятно, почему такой подход с собственным языком, который компилируется в другой интерпретируемый язык, возникает, в основном, вокруг JS?

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

                                                    Так чем же программисты на JS отличаются от остальных?
                                                +2
                                                Во-вторых, это структурность ( ООП, модули, пакеты… ), которую не так просто достичь на чистом JavaScript. На данный момент существуют 3 языка, обладающие почти всеми перечисленным качествами

                                                Зачем еще один отдельный язык? Пора бы начинать использовать ES6, который все это предусматривает. Google Traceur уже отлично справляется со своей задачей транс-компиляции, и имеет маленький рантайм. Со временем это будет поддерживаться браузерами нативно и необходимость в Traceur отпадет.
                                                  0
                                                  Интересная разработка. Не глядя на критику в теме (впрочем, статья у вас действительно получилась «бедная»), всё равно продолжайте разработку. Прогресс часто двигается именно строителями велосипедов, которым удаётся придумать, как сделать привычные вещи удобнее.
                                                    +1
                                                    Хорошо, он умеет биндить main в addEventListener и форматировать строки. Что ещё?
                                                    0
                                                    Нужно уже Top500 таких языков составлять.

                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                  Самое читаемое