From d0740d0ba443f0f24c78d321e15b41bb6c45cecd Mon Sep 17 00:00:00 2001 From: Gabriel Dos Reis Date: Wed, 30 Dec 2015 00:54:19 -0800 Subject: Move bemol.cc's Fragment to core library. --- src/io/InputFragment.cxx | 87 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) (limited to 'src/io') diff --git a/src/io/InputFragment.cxx b/src/io/InputFragment.cxx index dad38db2..394f670f 100644 --- a/src/io/InputFragment.cxx +++ b/src/io/InputFragment.cxx @@ -1,5 +1,5 @@ // -*- C++ -*- -// Copyright (C) 2014, Gabriel Dos Reis. +// Copyright (C) 2014-2015, Gabriel Dos Reis. // All rights reserved. // Written by Gabriel Dos Reis. // @@ -35,7 +35,10 @@ #include #include #include +#include #include +#include +#include namespace OpenAxiom { // Formatting program fragments. @@ -44,4 +47,86 @@ namespace OpenAxiom { std::ostream_iterator(os, "\n")); return os; } + + // Return the indentation level of a line. + // FIXME: reject or expand tabs as appropriate. + static ColumnIndex indentation(const Line& line) { + ColumnIndex idx { }; + for (auto c : line) { + if (not isblank(c)) + break; + ++idx; + } + return idx; + } + + // Remove trailing white-space characters from the line. + static Line& trim_right(Line& line) { + auto n = line.length(); + while (n > 0 and isblank(line[n-1])) + --n; + line.resize(n); + return line; + } + + // Clean up and dress up the line with indentation information. + static Line& prop_up(Line& line) { + line.indent = indentation(trim_right(line)); + return line; + } + + // Return true if line is entirely a positive comment, i.e. a description. + static bool positive_comment(const Line& line) { + if (line.indent + 1 >= line.length()) + return false; + return line[line.indent] == '+' and line[line.indent + 1] == '+'; + } + + // Return true if line is entirely a negative comment. + static bool negative_comment(const Line& line) { + if (line.indent + 1 >= line.length()) + return false; + return line[line.indent] == '-' and line[line.indent + 1] == '-'; + } + + // Return true if line is either empty or a negative comment. + static bool blank(const Line& line) { + return line.empty() or negative_comment(line); + } + + // Decompose the input souce file into fragments, and return one + // fragment at a time. + Fragment SourceInput::get() { + Fragment fragment; + std::stack indents; + + if (not line.empty()) { + indents.push(line.indent); + fragment.push_back(line); + } + + while (std::getline(input, line)) { + ++line.number; + if (blank(prop_up(line))) + continue; // Don't bother with ignorable comments. + else if (fragment.line_continuation()) + ; + else if (indents.empty()) { + if (fragment.empty() and line.indent != 0) + std::cerr << "warning: white space at begining of fragment" + << " on line " << line.number << '\n'; + indents.push(line.indent); + } + else if (line.indent == 0 and not positive_comment(fragment.back())) + break; // A completely new line; save for later. + else if (line.indent > indents.top()) + indents.push(line.indent); + else { + while (line.indent < indents.top()) + indents.pop(); + } + fragment.push_back(line); + } + return fragment; + } } -- cgit v1.2.3