Выразительный JavaScript (Хавербеке) - страница 120

>  return value;

>};

Окружение

Окружение, принимаемое интерпретатором — это объект со свойствами, чьи имена соответствуют именам переменных, а значения – значениям этих переменных. Давайте определим объект окружения, представляющий глобальную область видимости.

Для использования конструкции >if мы должны создать булевские значения. Так как их всего два, особый синтаксис для них не нужен. Мы просто делаем две переменные со значениями >true и >false.

>var topEnv = Object.create(null);


>topEnv["true"] = true;

>topEnv["false"] = false;

Теперь мы можем вычислить простое выражение, меняющее булевское значение на обратное.

>var prog = parse("if(true, false, true)");

>console.log(evaluate(prog, topEnv)); // → false

Для поддержки простых арифметических операторов и сравнения мы добавим несколько функций в окружение. Для упрощения кода мы будем использовать >new Function для создания набора функций-операторов в цикле, а не определять их все по отдельности.

>["+", "-", "*", "/", "==", "<", ">"].forEach(function(op) {

>  topEnv[op] = new Function("a, b", "return a " + op + " b;");

>});

Также пригодится способ вывода значений, так что мы обернём >console.log в функцию и назовём её >print.

>topEnv["print"] = function(value) {

>  console.log(value);

>  return value;

>};

Это даёт нам достаточно элементарных инструментов для написания простых программ. Следующая функция >run даёт удобный способ записи и запуска. Она создаёт свежее окружение, парсит и разбирает строчки, которые мы ей передаём, так, как будто они являются одной программой.

>function run() {

>  var env = Object.create(topEnv);

>  var program = Array.prototype.slice

>    .call(arguments, 0).join("\n");

>  return evaluate(parse(program), env);

>}

Использование >Array.prototype.slice.call – уловка для превращения объекта, похожего на массив, такого как аргументы, в настоящий массив, чтобы мы могли применить к нему >join. Она принимает все аргументы, переданные в >run, и считает, что все они – строчки программы.

>run("do(define(total, 0),",

>    "   define(count, 1),",

>    "   while(<(count, 11),",

>    "         do(define(total, +(total, count)),",

>    "            define(count, +(count, 1)))),",

>    "   print(total))");

>// → 55

Эту программу мы видели уже несколько раз – она подсчитывает сумму чисел от 1 до 10 на языке Egg. Она уродливее эквивалентной программы на JavaScript, но не так уж и плоха для языка, заданного менее чем 150 строчками кода.

Функции

Язык программирования без функций – плохой язык.

К счастью, несложно добавить конструкцию >fun, которая расценивает последний аргумент как тело функции, а все предыдущие – имена аргументов функции.