Cerata
A library to generate structural hardware designs
block.cc
1 // Copyright 2018-2019 Delft University of Technology
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "cerata/vhdl/block.h"
16 
17 #include <regex>
18 #include <string>
19 #include <iostream>
20 #include <sstream>
21 
22 namespace cerata::vhdl {
23 
24 static std::string tab(int n) {
25  return std::string(static_cast<uint64_t>(2 * n), ' ');
26 }
27 
28 Line &operator<<(Line &lhs, const std::string &str) {
29  lhs.parts.push_back(str);
30  return lhs;
31 }
32 
33 Line &operator<<(Line &lhs, const Line &rhs) {
34  lhs.parts.insert(lhs.parts.end(), rhs.parts.begin(), rhs.parts.end());
35  return lhs;
36 }
37 
38 Line &operator+=(Line &lhs, const std::string &str) { //NOLINT
39  lhs.parts.back().append(str);
40  return lhs;
41 }
42 
43 std::vector<size_t> Block::GetAlignments() const {
44  std::vector<size_t> ret = {0};
45  for (const auto &l : lines) {
46  for (size_t p = 0; p < l.parts.size(); p++) {
47  if (p >= ret.size()) {
48  ret.push_back(l.parts[p].length());
49  } else if (l.parts[p].length() > ret[p]) {
50  ret[p] = l.parts[p].length();
51  }
52  }
53  }
54  return ret;
55 }
56 
57 std::string Block::ToString() const {
58  std::stringstream ret;
59  auto a = GetAlignments();
60  for (const auto &l : lines) {
61  std::stringstream m;
62  m << tab(indent);
63  for (size_t p = 0; p < l.parts.size(); p++) {
64  auto align = a[p];
65  auto plen = l.parts[p].length();
66  auto diff = align - plen;
67  if (diff != 0) {
68  auto padding = std::string(diff, ' ');
69  m << l.parts[p] + padding;
70  } else {
71  m << l.parts[p];
72  }
73  }
74  // strip trailing whitespace
75  ret << std::regex_replace(m.str(), std::regex("\\s+$"), std::string("")) + "\n";
76  }
77  return ret.str();
78 }
79 
81  std::reverse(lines.begin(), lines.end());
82  return *this;
83 }
84 
85 Block &Block::Sort(std::optional<char> c) {
86  std::stable_sort(lines.begin(), lines.end(),
87  [&](const Line &la, const Line &lb) -> bool {
88  auto a = la.ToString();
89  auto b = lb.ToString();
90  if (c) {
91  return a.substr(0, a.find_first_of(*c)) > b.substr(0, b.find_first_of(*c));
92  } else {
93  return a > b;
94  }
95  });
96  return *this;
97 }
98 
99 Block &Block::AppendBlankLineIfNotEmpty() {
100  if (!lines.empty()) {
101  if (!lines.back().IsBlank()) {
102  lines.emplace_back();
103  }
104  }
105  return *this;
106 }
107 
108 Block &operator<<(Block &lhs, const Line &line) {
109  lhs.lines.push_back(line);
110  return lhs;
111 }
112 
113 Block &operator<<(Block &lhs, const Block &rhs) {
114  lhs.lines.insert(std::end(lhs.lines), std::begin(rhs.lines), std::end(rhs.lines));
115  return lhs;
116 }
117 
118 Block &Prepend(const std::string &lhs, Block *rhs, const std::string &sep) {
119  if (!lhs.empty()) {
120  for (auto &l : rhs->lines) {
121  if (!l.parts.empty()) {
122  if (l.parts.front() == " : ") {
123  l.parts.insert(l.parts.begin(), lhs);
124  } else {
125  l.parts.front() = lhs + sep + l.parts.front();
126  }
127  } else {
128  l << lhs;
129  }
130  }
131  }
132  return *rhs;
133 }
134 
135 Block &operator<<(Block &lhs, const std::string &rhs) {
136  if (!lhs.lines.empty()) {
137  for (auto &l : lhs.lines) {
138  if (!l.parts.empty()) {
139  l.parts.back().append(rhs);
140  }
141  }
142  } else {
143  Line t;
144  t << rhs;
145  lhs << t;
146  }
147  return lhs;
148 }
149 
150 Block &operator<<=(Block &lhs, const std::string &rhs) { //NOLINT
151  if (!lhs.lines.empty()) {
152  for (size_t i = 0; i < lhs.lines.size() - 1; i++) {
153  lhs.lines[i].parts.back().append(rhs);
154  }
155  }
156  return lhs;
157 }
158 
159 MultiBlock &operator<<(MultiBlock &lhs, const Block &rhs) {
160  lhs.blocks.push_back(rhs);
161  return lhs;
162 }
163 
164 MultiBlock &operator<<(MultiBlock &lhs, const Line &rhs) {
165  Block tmp(lhs.indent);
166  tmp << rhs;
167  lhs << tmp;
168  return lhs;
169 }
170 
172  for (const auto &b : rhs.blocks) {
173  lhs << b;
174  }
175  return lhs;
176 }
177 
178 std::string MultiBlock::ToString() const {
179  std::stringstream ret;
180  for (const auto &b : blocks) {
181  ret << b.ToString();
182  }
183  return ret.str();
184 }
185 
186 std::string ToString(const std::vector<Block> &blocks) {
187  std::stringstream ret;
188  for (const auto &b : blocks) {
189  ret << b.ToString();
190  }
191  return ret.str();
192 }
193 
194 std::string Line::ToString() const {
195  std::stringstream str;
196  for (const auto &p : parts) {
197  str << p;
198  }
199  return str.str();
200 }
201 } // namespace cerata::vhdl
cerata::dot::tab
std::string tab(uint n)
Return indent string.
Definition: style.h:28
cerata::operator<<=
std::shared_ptr< Edge > operator<<=(Node *dst, const std::shared_ptr< Node > &src)
Create an edge, connecting the src node to the dst node.
Definition: edge.cc:168
cerata::vhdl::Line::parts
std::vector< std::string > parts
The parts of the line of code.
Definition: block.h:46
cerata::vhdl::MultiBlock
A structure to hold multiple blocks.
Definition: block.h:77
cerata::vhdl::Block::lines
std::vector< Line > lines
Lines in the blocks.
Definition: block.h:71
cerata::vhdl::Block::ToString
std::string ToString() const
Return this block as a single string.
Definition: block.cc:57
cerata::vhdl::MultiBlock::blocks
std::vector< Block > blocks
The blocks in this multiblock.
Definition: block.h:83
cerata::vhdl::Line
A line of code.
Definition: block.h:25
cerata::vhdl::MultiBlock::indent
int indent
Indent level.
Definition: block.h:85
cerata::ToString
std::string ToString(Expression::Op operation)
Human-readable expression operator.
Definition: expression.cc:149
cerata::vhdl::Prepend
Block & Prepend(const std::string &lhs, Block *rhs, const std::string &sep)
Prepend a string to every line of a block.
Definition: block.cc:118
cerata::vhdl::operator+=
Line & operator+=(Line &lhs, const std::string &str)
Append a string to the last line part.
Definition: block.cc:38
cerata::vhdl::MultiBlock::ToString
std::string ToString() const
Return this multiblock as a single string.
Definition: block.cc:178
cerata::vhdl::Block
A block of code.
Definition: block.h:50
cerata::vhdl::operator<<
Line & operator<<(Line &lhs, const std::string &str)
Append a part to a line.
Definition: block.cc:28
cerata::vhdl::Block::Sort
Block & Sort(std::optional< char > c=std::nullopt)
Sort the lines in the block. Supply a character to stop sorting per line after encountering the chara...
Definition: block.cc:85
cerata::vhdl::Block::indent
int indent
Indenting level of the block.
Definition: block.h:73
cerata::vhdl::Block::Reverse
Block & Reverse()
Return the block in reverse.
Definition: block.cc:80
cerata::vhdl::Block::GetAlignments
std::vector< size_t > GetAlignments() const
Return the alignment for each line.
Definition: block.cc:43
cerata::vhdl
Contains everything related to the VHDL back-end.
Definition: architecture.cc:31