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

Визуализация - отличный способ запечатлеть ментальные модели; особенно для установления интимной связи с данными. Учитывая, что AST - это деревья, имеет смысл визуализировать данные в иерархической структуре, чтобы обосновать нашу ментальную модель.

Инструмент, который вы создадите, состоит из 2 компонентов - редактора кода и вкладки с 3 разделами: структура дерева, использование конструкции и сам AST. Если вы хотите продолжить, возьмите копию с GitHub.

Демо

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

  1. Создать макет страницы
  2. Вставьте редактор кода в левый контейнер
  3. Вставьте вкладку в правый контейнер
  4. Слушайте изменения кода и генерируйте AST
  5. Визуализировать AST

Для макета давайте воспользуемся materializecss - с этой библиотекой создание адаптивного макета займет пару шагов.

<div class="row"> 
   <div class="col s12 m4 l3"></div>
   <div class="col s12 m8 l9"> </div> 
</div>

Теперь, когда у нас есть макет, давайте перейдем к созданию нашего первого компонента - редактора кода. Редакторы кода хороши тем, что позволяют пользователям копаться в ваших API и фрагментах кода. CodeFlask - один из таких редакторов микрокода, который можно использовать на веб-страницах. Его использование не может быть проще -

let flask = new CodeFlask; 
let defaultCode = "function init() {\n console.log('hello world'); \n} \ninit();"; 
flask.run('#my-code-wrapper', { language: 'js' }); flask.update(defaultCode);

Codeflask также предоставляет хуки onUpdate. По мере того, как пользователь вводит тип, полный блок кода передается в качестве параметра String функции обратного вызова.

flask.onUpdate((code) => { 
 let ast = generateAst(code); 
 renderVisuals(ast); 
});

Двигаясь дальше, нам нужно преобразовать код в AST. Введите Esprima - при вызове метода синтаксического анализа для esprima со строкой кода в качестве параметра создается AST.

let ast = esprima.parse(code);

Как только AST сгенерирован, мир открыт для вас. Вы можете перемещаться по нему, чтобы внести необходимые изменения. В нашем случае мы используем библиотеку обхода ast-traverse для нормализации данных для визуализации. Если вы внимательный наблюдатель, вы могли заметить, что AST не обязательно имеет массив элементов в свойстве body. Поскольку наша библиотека визуализации требует, чтобы к родительскому элементу был прикреплен массив дочерних элементов, мы нормализуем данные, оборачивая все свойство тела объектом в виде массива. По мере того, как мы проходили, мы также можем изменять значения или любые другие конструкции, но для краткости этого достаточно.

Наконец-то мы подошли к последнему этапу нашего плана действий - визуализации AST. Поскольку мы также будем считать конструкции и отображать AST, давайте обернем весь наш контент на вкладки. К счастью для нас, materializecss предлагает виджет вкладок. Здорово! сшить их. Содержание нашей первой вкладки будет представлять визуальный элемент. Среди множества библиотек визуализации javascript давайте воспользуемся популярной библиотекой - d3.js. Он предлагает различные макеты, такие как связка, аккорд, сила, иерархия, раздел, круговая диаграмма, стек, гистограмма, упаковка, дерево, кластер и Древовидная карта. Наш интерес представляет древовидная структура.

Создание визуального элемента дерева с помощью d3.js включает объявление макета дерева, преобразование данных и сопоставление преобразованных данных с макетом дерева. В результате получился декорированный объект d3 на стероидах.

// declares a tree layout and assigns the size 
let treemap = d3.tree().size([width, height]); 
// assigns the data to a hierarchy using parent-child relationships let nodes = d3.hierarchy(treeData); 
// maps the node data to the tree layout 
nodes = treemap(nodes);

После преобразования и нормализации данных все готово к запуску. Первым делом создайте базовый элемент SVG.

var svg = d3.select(container).append("svg"); 
..

Затем создаем элементы SVG «Path» для соединения узлов. Возвращенный массив из вызова nodes.descendants () используется для создания путей с классом link.

let link = svg.selectAll(".link")          .data(nodes.descendants().slice(1)) 
.enter()
.append("path") 
.attr("class", "link") 
.attr("d", function (d) { 
   return "M" + d.x + "," + d.y + "C" + d.x + "," + (d.y + d.parent.y) / 2 + " " + d.parent.x + "," + (d.y + d.parent.y) / 2 + " " + d.parent.x + "," + d.parent.y; 
});

Тот же вызов nodes.descendants () также передает данные для создания элементов SVG «круга».

let node = g.selectAll(".node") 
.data(nodes.descendants()) 
.enter()
.append("g") 
.attr("class", function (d) { 
   return "node" + (d.children ? " node--internal" : " node--leaf"); }) 
.attr("transform", function (d) {
   return "translate(" + d.x + "," + d.y + ")"; 
}); 
node.append("circle") 
.attr("r", 10);

После создания узлов мы добавляем к ним «текстовый» элемент.

node.append("text") 
.attr({ 
    "dy": ".35em", 
    "y": function (d) { return d.children ? -20 : 20; }
  }) 
.text(function (d) { return d.data.type; });

Вот и все! Есть еще 2 вкладки, которые дополняют нашу визуализацию - Использование и AST. Чтобы подсчитать каждый тип конструкции и частоту ее использования, давайте вернемся к нашему набору инструментов для ast-traverse.

let hash = {}; 
traverse(ast,{ post: function (node) { hash.hasOwnProperty(node.type) ? hash[node.type] = hash[node.type] + 1 : hash[node.type] = 1; } });

Когда у нас есть объект с типом и количеством, создайте элемент таблицы, переберите каждое свойство и создайте строку.

Наконец, чтобы отобразить AST, создайте еще один экземпляр CodeFlask и обновите редактор с помощью AST. Это вполне может быть текстовое поле, но CodeFlask предлагает форматирование и цвета, так почему бы и нет.

Собирая все вместе, код в редакторе трансформируется в AST, который визуализируется и анализируется. В одном из следующих постов мы рассмотрим использование AST для решения реальных программных проблем.

Первоначально опубликовано на javascriptstore.com 15 октября 2017 г.