* это перевод статьи с DailyJS
Введение
LispyScript — древовидный язык программирования, который компилится в JavaScript. Собственно говоря, это что-то между JavaScript и Lisp.
Скрипт на Lispy состоит из подобных выражений:
(<function> arg1 arg2 arg3 ...)
Данное выражение вызывает функцию (вообще это не совсем так, но это позже).
Первый элемент указывает на функцию. Остальные — аргументы.
(console.log "abc")
Да, совсем забыл: поиграться можно тут.
Можно вызвать вот так:
(console.log "2 + 2 = %d" (+ 2 2))
В JS это так:
console.log("2 + 2 = %d", (2 + 2));
Ну а теперь всем нам знакомая структура HTML:
<html lang="en">
<head>
<title>My Home Page</title>
</head>
<body>
<h1>Welcome to LispyScript</h1>
</body>
</html>
А теперь шаблоны Lispy:
(html {lang: "en"}
(head
(title "My Home Page"))
(body
(h1 "Welcome to LispyScript")))
Про шаблоны позже, сейчас важно увидеть древовидную структуру.
Макросы
Одна из важнейших частей Lispy. Макросы никак не компилятся в JS, но они расширяют компилятор. Давайте напишем макрос print:
(macro print (str rest...)
(console.log ~str ~rest...))
(print "Hello print macro!")
(print "2 + 2 = %d" (+ 2 2))
console.log("Hello print macro!")
console.log("2 + 2 = %d", (2 + 2));
Приведённый выше макрос расширяет Lispy. Выражение macro принимает первым параметром имя макроса, дальше в скобках параметры, а затем код, в который компилируется вызов макроса.
Оператор ~ разыменует параметры. Переменная rest… содержит все переданные параметры, идущие после str.
Компилятор работает в 2 этапа: вначале макрос преобразует код. Т.е. из
(print "Hello print macro!")
Он создаёт:
(console.log "Hello print macro!")
Ну а дальше уже компилит в JS. Аналогично:
(print "2 + 2 = %d" (+ 2 2)) ; lispy
(console.log "2 + 2 = %d" (+ 2 2)) ; lispy
console.log("2 + 2 = %d", (2 + 2)); // js
Можно спросить, а почему не использовать вместо макроса функцию? Давайте попробуем:
(var print
(function (data value)
(console.log data value)))
А теперь сравните получившийся код:
// макрос
console.log("2 + 2 = %d", (2 + 2));
// функция
var print = function(data,value) {
return console.log(data,value);
};
print("2 + 2 = %d",(2 + 2));
Макросы могут быть опасны
Не надо ждать от макроса, что он будет вести себя как функция. Очень часто лучше использовать функцию вместо макроса.
Пример: напишем макрос для вычисления квадрата числа:
(macro square (x)
(* ~x ~x))
(console.log (square 2))
И этот код будет прекрасно работать, выведет 4. В JS это так:
console.log((2 * 2));
А теперь пробуем:
(var i 2)
(console.log (square i++))
И у нас возвращается число 6 вместо 9. Всё сразу становится понятно, если взглянуть на скомпиленный код:
var i = 2;
console.log((i++ * i++));
В случае функции значение вычисляется заранее, а вот в случае макроса — нет. Так что это нужно запомнить и понять.
Заключение
В общем, Lispy прелагает альтернативный путь написания скриптов. Макросы являются очень мощным средством, но их лучше использовать с осторожностью.
P. S.
Также есть Javathcript. Правда он без макросов.
Автор: Keyten