Окружение, принимаемое интерпретатором — это объект со свойствами, чьи имена соответствуют именам переменных, а значения – значениям этих переменных. Давайте определим объект окружения, представляющий глобальную область видимости.
Для использования конструкции >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 строчками кода.