Skip to content

tree version of the ast printer #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 155 additions & 82 deletions include/boost/boostache/vm/printer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,96 +2,169 @@
* \file vm/printer.hpp
*
* Copyright 2014, 2015 Michael Caisse : ciere.com
* Copyright 2014, 2015 Michal Bukovsky
*
* Distributed under the Boost Software License, Version 1.0. (See accompanying
* file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
*/

#ifndef BOOST_BOOSTACHE_VM_PRINTER_HPP
#define BOOST_BOOSTACHE_VM_PRINTER_HPP

#include <boost/variant/apply_visitor.hpp>
#include <boost/boostache/vm/engine_ast.hpp>

namespace boost { namespace boostache { namespace vm { namespace ast
namespace boost { namespace boostache {
namespace vm { namespace ast { namespace detail {

class printer
{
public:
typedef void result_type;

printer(std::ostream &out)
: out{out}, decorations{true}
{}

void operator()(undefined)
{
print_decoration();
out << "[<undefined>]" << std::endl;
}

void operator()(literal const & v)
{
print_decoration();
out << "[<literal>: \"" << shrink(v.value) << "\"]" << std::endl;
}

void operator()(variable const & v)
{
print_decoration();
out << "[<variable>: " << v.name << "]" << std::endl;
}

void operator()(render const & v)
{
print_decoration();
out << "[<render>: " << v.name << "]" << std::endl;
}

void operator()(for_each const & v)
{
print_decoration();
out << "[<for_each>: " << v.name << "]" << std::endl;
indent_decoration(v.value);
boost::apply_visitor(*this, v.value);
undent_decoration();
}

void operator()(condition const & v)
{}

void operator()(select_context const & v)
{
print_decoration();
out << "[<select>: " << v.tag << "]" << std::endl;
indent_decoration(v.body);
boost::apply_visitor(*this, v.body);
undent_decoration();
}

void operator()(if_then_else const & v)
{
print_decoration();
out << "[<if>: " << v.condition_.name << "]" << std::endl;

indent_decoration(true);
print_decoration();
out << "[<then>]" << std::endl;
indent_decoration(v.then_);
boost::apply_visitor(*this, v.then_);
undent_decoration();
undent_decoration();

indent_decoration(false);
print_decoration();
out << "[<else>]" << std::endl;
indent_decoration(v.else_);
boost::apply_visitor(*this, v.else_);
undent_decoration();
undent_decoration();
}

void operator()(node_list const & v)
{
for (auto inode = v.nodes.begin(),
enode = v.nodes.end();
inode != enode; ++inode)
{
if (std::next(inode) == enode) decorations.back() = false;
boost::apply_visitor(*this, *inode);
}
}

private:
std::string shrink(std::string v)
{
std::transform(v.begin(), v.end(), v.begin(), [] (char ch) {
return (std::isgraph(ch) || std::isblank(ch))? ch: '%';
});
if (v.size() > 30) {
v.resize(30);
v.append("...");
}
return v;
}

class is_multi_node
{
public:
typedef bool result_type;

template <typename T>
bool operator()(const T &) const { return false;}

bool operator()(const node_list &) const { return true;}
};

void print_decoration()
{
for (auto idecoration = decorations.begin(),
edecoration = decorations.end();
idecoration != edecoration; ++idecoration)
{
if (std::next(idecoration) == edecoration)
out << (*idecoration? "├──": "└──");
else
out << (*idecoration? "│ ": " ");
}

}

void indent_decoration(const node &node)
{
decorations.emplace_back(boost::apply_visitor(is_multi_node{}, node));
}

void indent_decoration(bool multi) { decorations.emplace_back(multi);}

void undent_decoration() { decorations.pop_back();}

std::ostream &out;
std::vector<bool> decorations;
};

} // namespace detail

inline void print(std::ostream& out, node const& root)
{
namespace detail
{
class printer
{
public:
typedef void result_type;

printer(std::ostream& out)
: out(out)
{}

void operator()(undefined) const
{
out << "[<UNDEFINED>]";
}

void operator()(literal const & v) const
{
out << "[<literal node> : " << v.value << "]";
}

void operator()(variable const & v) const
{
out << "[<variable> : " << v.name << "]";
}

void operator()(render const & v) const
{
out << "[<render> : " << v.name << "]";
}

void operator()(for_each const & v) const
{
out << "[<for_each> :" << std::endl;
boost::apply_visitor(*this, v.value);
out << "\n</for_each>]" << std::endl;
}

void operator()(condition const & v) const
{}

void operator()(select_context const & v) const
{
out << "[<select_context> [" << v.tag << "] :" << std::endl;
boost::apply_visitor(*this, v.body);
out << "\n</select_context>]" << std::endl;
}

void operator()(if_then_else const & v) const
{
out << "[<if> : --------------------------- " << std::endl;
//boost::apply_visitor(*this, v.condition_);
out << "[<then> : --------------------------- " << std::endl;
boost::apply_visitor(*this, v.then_);
out << "\n]\n";
out << "[<else> : --------------------------- " << std::endl;
boost::apply_visitor(*this, v.else_);
out << "\n</if>]" << std::endl;
}

void operator()(node_list const & v) const
{
for(auto const & node : v.nodes)
{
boost::apply_visitor(*this, node);
}
}

private:
std::ostream& out;
};
}

inline void print(std::ostream& out, node const& root)
{
detail::printer p(out);
boost::apply_visitor(p, root);
}
}}}}

#endif
out << "┐\n";
detail::printer p(out);
boost::apply_visitor(p, root);
}

}}}} // namespace boost::boostache::vm::ast

#endif /* BOOST_BOOSTACHE_VM_PRINTER_HPP */