Skip to content

Commit

Permalink
Break out PrintVisitor into separate file.
Browse files Browse the repository at this point in the history
  • Loading branch information
hzeller committed Jun 27, 2024
1 parent 9f74f46 commit 5893b61
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 136 deletions.
2 changes: 2 additions & 0 deletions bant/frontend/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,13 @@ cc_library(
srcs = [
"ast.cc",
"parser.cc",
"print-visitor.cc",
"scanner.cc",
],
hdrs = [
"ast.h",
"parser.h",
"print-visitor.h",
"scanner.h",
],
deps = [
Expand Down
114 changes: 0 additions & 114 deletions bant/frontend/ast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@

#include <charconv>
#include <cstdint>
#include <ostream>
#include <string>
#include <string_view>
#include <system_error>

#include "bant/frontend/scanner.h"
#include "bant/util/arena.h"

namespace bant {
Expand Down Expand Up @@ -76,115 +73,4 @@ StringScalar *StringScalar::FromLiteral(Arena *arena,
return arena->New<StringScalar>(literal, is_triple_quoted, is_raw);
}

void PrintVisitor::VisitFunCall(FunCall *f) {
out_ << f->identifier()->id();
BaseVoidVisitor::VisitFunCall(f);
}

static void PrintListTypeOpen(List::Type t, std::ostream &out) {
switch (t) {
case List::Type::kList: out << "["; break;
case List::Type::kMap: out << "{"; break;
case List::Type::kTuple: out << "("; break;
}
}
static void PrintListTypeClose(List::Type t, std::ostream &out) {
switch (t) {
case List::Type::kList: out << "]"; break;
case List::Type::kMap: out << "}"; break;
case List::Type::kTuple: out << ")"; break;
}
}

void PrintVisitor::VisitList(List *l) {
static constexpr int kIndentSpaces = 4;
PrintListTypeOpen(l->type(), out_);
const bool needs_multiline = (l->size() > 1);
if (needs_multiline) out_ << "\n";
indent_ += kIndentSpaces;
bool is_first = true;
for (Node *node : *l) {
if (!is_first) out_ << ",\n";
if (needs_multiline) out_ << std::string(indent_, ' ');
if (!WalkNonNull(node)) {
out_ << "NIL";
}
is_first = false;
}
// If a tuple only contains one element, then we need a final ','
// to disambiguate from a parenthesized expression.
if (l->type() == List::Type::kTuple && l->size() == 1) {
out_ << ",";
}

indent_ -= kIndentSpaces;
if (needs_multiline) {
out_ << "\n" << std::string(indent_, ' ');
}
PrintListTypeClose(l->type(), out_);
}

void PrintVisitor::VisitUnaryExpr(UnaryExpr *e) {
out_ << e->op();
if (e->op() == TokenType::kNot) out_ << " ";
WalkNonNull(e->node());
}

void PrintVisitor::VisitBinOpNode(BinOpNode *b) {
WalkNonNull(b->left());
if (b->op() == '.' || b->op() == '[') {
out_ << b->op(); // No spacing around some operators.
} else {
out_ << " " << b->op() << " ";
}
WalkNonNull(b->right());
if (b->op() == '[') { // Array access is a BinOp with '[' as op.
out_ << "]";
}
}

void PrintVisitor::VisitListComprehension(ListComprehension *lh) {
PrintListTypeOpen(lh->type(), out_);
WalkNonNull(lh->for_node());
PrintListTypeClose(lh->type(), out_);
}

void PrintVisitor::VisitTernary(Ternary *t) {
WalkNonNull(t->positive());
out_ << " if ";
WalkNonNull(t->condition());
if (t->negative()) {
out_ << " else ";
t->negative()->Accept(this);
}
}

void PrintVisitor::VisitScalar(Scalar *s) {
if (s->type() == Scalar::ScalarType::kInt) {
if (s->AsString().empty()) {
out_ << s->AsInt();
} else {
out_ << s->AsString(); // Keep original representation intact if avail.
}
} else {
const StringScalar *str = static_cast<StringScalar *>(s);
if (str->is_raw()) out_ << "r";
// Minimal-effort quote char choosing. TODO: look if escaped
const bool has_any_double_quote =
str->AsString().find_first_of('"') != std::string_view::npos;
const char quote_char = has_any_double_quote ? '\'' : '"';
if (str->is_triple_quoted()) out_ << quote_char << quote_char;
out_ << quote_char << str->AsString() << quote_char;
if (str->is_triple_quoted()) out_ << quote_char << quote_char;
}
}

void PrintVisitor::VisitIdentifier(Identifier *i) { out_ << i->id(); }

std::ostream &operator<<(std::ostream &o, Node *n) {
if (!PrintVisitor(o).WalkNonNull(n)) {
o << "NIL";
}
return o;
}
} // namespace bant
26 changes: 4 additions & 22 deletions bant/frontend/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ class Node {
virtual Node *Accept(NodeVisitor *v) = 0;
};

// Printing a node. If pointer is non-null, it is dereferenced and printed.
// (defined in print-visitor.*)
std::ostream &operator<<(std::ostream &o, Node *n);

class Scalar : public Node {
public:
enum class ScalarType { kInt, kString };
Expand Down Expand Up @@ -432,28 +436,6 @@ class BaseNodeReplacementVisitor : public NodeVisitor {
void ReplaceWalk(Node **n) { *n = WalkNonNull(*n); }
};

class PrintVisitor : public BaseVoidVisitor {
public:
explicit PrintVisitor(std::ostream &out) : out_(out) {}
// Using default impl. for Assignment.
void VisitFunCall(FunCall *f) final;
void VisitList(List *l) final;

void VisitUnaryExpr(UnaryExpr *e) final;
void VisitBinOpNode(BinOpNode *b) final;
void VisitListComprehension(ListComprehension *lh) final;
void VisitTernary(Ternary *t) final;

void VisitScalar(Scalar *s) final;
void VisitIdentifier(Identifier *i) final;

private:
int indent_ = 0;
std::ostream &out_;
};

std::ostream &operator<<(std::ostream &o, Node *n);

// VoidVisitor Accept()ors
inline void Assignment::Accept(VoidVisitor *v) { v->VisitAssignment(this); }
inline void FunCall::Accept(VoidVisitor *v) { v->VisitFunCall(this); }
Expand Down
1 change: 1 addition & 0 deletions bant/frontend/parsed-project.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "bant/explore/query-utils.h"
#include "bant/frontend/ast.h"
#include "bant/frontend/parser.h"
#include "bant/frontend/print-visitor.h"
#include "bant/frontend/scanner.h"
#include "bant/frontend/source-locator.h"
#include "bant/session.h"
Expand Down
138 changes: 138 additions & 0 deletions bant/frontend/print-visitor.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// bant - Bazel Navigation Tool
// Copyright (C) 2024 Henner Zeller <[email protected]>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

#include "bant/frontend/print-visitor.h"

#include <ostream>
#include <string>

#include "bant/frontend/ast.h"
#include "bant/frontend/scanner.h"

namespace bant {
void PrintVisitor::VisitFunCall(FunCall *f) {
out_ << f->identifier()->id();
BaseVoidVisitor::VisitFunCall(f);
}

static void PrintListTypeOpen(List::Type t, std::ostream &out) {
switch (t) {
case List::Type::kList: out << "["; break;
case List::Type::kMap: out << "{"; break;
case List::Type::kTuple: out << "("; break;
}
}
static void PrintListTypeClose(List::Type t, std::ostream &out) {
switch (t) {
case List::Type::kList: out << "]"; break;
case List::Type::kMap: out << "}"; break;
case List::Type::kTuple: out << ")"; break;
}
}

void PrintVisitor::VisitList(List *l) {
static constexpr int kIndentSpaces = 4;
PrintListTypeOpen(l->type(), out_);
const bool needs_multiline = (l->size() > 1);
if (needs_multiline) out_ << "\n";
indent_ += kIndentSpaces;
bool is_first = true;
for (Node *node : *l) {
if (!is_first) out_ << ",\n";
if (needs_multiline) out_ << std::string(indent_, ' ');
if (!WalkNonNull(node)) {
out_ << "NIL";
}
is_first = false;
}
// If a tuple only contains one element, then we need a final ','
// to disambiguate from a parenthesized expression.
if (l->type() == List::Type::kTuple && l->size() == 1) {
out_ << ",";
}

indent_ -= kIndentSpaces;
if (needs_multiline) {
out_ << "\n" << std::string(indent_, ' ');
}
PrintListTypeClose(l->type(), out_);
}

void PrintVisitor::VisitUnaryExpr(UnaryExpr *e) {
out_ << e->op();
if (e->op() == TokenType::kNot) out_ << " ";
WalkNonNull(e->node());
}

void PrintVisitor::VisitBinOpNode(BinOpNode *b) {
WalkNonNull(b->left());
if (b->op() == '.' || b->op() == '[') {
out_ << b->op(); // No spacing around some operators.
} else {
out_ << " " << b->op() << " ";
}
WalkNonNull(b->right());
if (b->op() == '[') { // Array access is a BinOp with '[' as op.
out_ << "]";
}
}

void PrintVisitor::VisitListComprehension(ListComprehension *lh) {
PrintListTypeOpen(lh->type(), out_);
WalkNonNull(lh->for_node());
PrintListTypeClose(lh->type(), out_);
}

void PrintVisitor::VisitTernary(Ternary *t) {
WalkNonNull(t->positive());
out_ << " if ";
WalkNonNull(t->condition());
if (t->negative()) {
out_ << " else ";
t->negative()->Accept(this);
}
}

void PrintVisitor::VisitScalar(Scalar *s) {
if (s->type() == Scalar::ScalarType::kInt) {
if (s->AsString().empty()) {
out_ << s->AsInt();
} else {
out_ << s->AsString(); // Keep original representation intact if avail.
}
} else {
const StringScalar *str = static_cast<StringScalar *>(s);
if (str->is_raw()) out_ << "r";
// Minimal-effort quote char choosing. TODO: look if escaped
const bool has_any_double_quote =
str->AsString().find_first_of('"') != std::string_view::npos;
const char quote_char = has_any_double_quote ? '\'' : '"';
if (str->is_triple_quoted()) out_ << quote_char << quote_char;
out_ << quote_char << str->AsString() << quote_char;
if (str->is_triple_quoted()) out_ << quote_char << quote_char;
}
}

void PrintVisitor::VisitIdentifier(Identifier *i) { out_ << i->id(); }

std::ostream &operator<<(std::ostream &o, Node *n) {
if (!PrintVisitor(o).WalkNonNull(n)) {
o << "NIL";
}
return o;
}
} // namespace bant
47 changes: 47 additions & 0 deletions bant/frontend/print-visitor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// bant - Bazel Navigation Tool
// Copyright (C) 2024 Henner Zeller <[email protected]>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

#ifndef BANT_PRINT_VISITOR_H
#define BANT_PRINT_VISITOR_H

#include <ostream>

#include "bant/frontend/ast.h"

namespace bant {
class PrintVisitor : public BaseVoidVisitor {
public:
explicit PrintVisitor(std::ostream &out) : out_(out) {}
// Using default impl. for Assignment.
void VisitFunCall(FunCall *f) final;
void VisitList(List *l) final;

void VisitUnaryExpr(UnaryExpr *e) final;
void VisitBinOpNode(BinOpNode *b) final;
void VisitListComprehension(ListComprehension *lh) final;
void VisitTernary(Ternary *t) final;

void VisitScalar(Scalar *s) final;
void VisitIdentifier(Identifier *i) final;

private:
int indent_ = 0;
std::ostream &out_;
};
} // namespace bant

#endif // BANT_PRINT_VISITOR_H

0 comments on commit 5893b61

Please sign in to comment.