summaryrefslogtreecommitdiff
path: root/src/io
diff options
context:
space:
mode:
authorBen Longbons <b.r.longbons@gmail.com>2014-10-29 14:56:55 -0700
committerBen Longbons <b.r.longbons@gmail.com>2014-10-29 14:56:55 -0700
commit1a00fe4ea75924bfe594c4d92073cc95eaa2f32d (patch)
treea6e8992e0821a998236a4dfb5d6f6194a0b7ce97 /src/io
parent469991120bcf550b6e2124203103876b6b7be918 (diff)
downloadtmwa-1a00fe4ea75924bfe594c4d92073cc95eaa2f32d.tar.gz
tmwa-1a00fe4ea75924bfe594c4d92073cc95eaa2f32d.tar.bz2
tmwa-1a00fe4ea75924bfe594c4d92073cc95eaa2f32d.tar.xz
tmwa-1a00fe4ea75924bfe594c4d92073cc95eaa2f32d.zip
Item AST
Diffstat (limited to 'src/io')
-rw-r--r--src/io/fwd.hpp2
-rw-r--r--src/io/line.cpp107
-rw-r--r--src/io/line.hpp59
-rw-r--r--src/io/line_test.cpp50
-rw-r--r--src/io/read.cpp38
-rw-r--r--src/io/read.hpp14
-rw-r--r--src/io/read_test.cpp61
-rw-r--r--src/io/span.cpp99
-rw-r--r--src/io/span.hpp90
9 files changed, 396 insertions, 124 deletions
diff --git a/src/io/fwd.hpp b/src/io/fwd.hpp
index 99268f4..5334fbd 100644
--- a/src/io/fwd.hpp
+++ b/src/io/fwd.hpp
@@ -34,5 +34,7 @@ namespace io
class ReadFile;
class WriteFile;
class AppendFile;
+ class LineReader;
+ class LineCharReader;
} // namespace io
} // namespace tmwa
diff --git a/src/io/line.cpp b/src/io/line.cpp
index a1cdf42..5d7e792 100644
--- a/src/io/line.cpp
+++ b/src/io/line.cpp
@@ -19,9 +19,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "../strings/astring.hpp"
-#include "../strings/mstring.hpp"
#include "../strings/zstring.hpp"
-#include "../strings/xstring.hpp"
#include "cxxstdio.hpp"
@@ -32,71 +30,6 @@ namespace tmwa
{
namespace io
{
- AString Line::message_str(ZString cat, ZString msg) const
- {
- MString out;
- if (column)
- out += STRPRINTF("%s:%u:%u: %s: %s\n"_fmt,
- filename, line, column, cat, msg);
- else
- out += STRPRINTF("%s:%u: %s: %s\n"_fmt,
- filename, line, cat, msg);
- out += STRPRINTF("%s\n"_fmt, text);
- out += STRPRINTF("%*c\n"_fmt, column, '^');
- return AString(out);
- }
-
- void Line::message(ZString cat, ZString msg) const
- {
- if (column)
- FPRINTF(stderr, "%s:%u:%u: %s: %s\n"_fmt,
- filename, line, column, cat, msg);
- else
- FPRINTF(stderr, "%s:%u: %s: %s\n"_fmt,
- filename, line, cat, msg);
- FPRINTF(stderr, "%s\n"_fmt, text);
- FPRINTF(stderr, "%*c\n"_fmt, column, '^');
- }
-
- AString LineSpan::message_str(ZString cat, ZString msg) const
- {
- assert (begin.column);
- assert (end.column);
- assert (begin.line < end.line || begin.column <= end.column);
-
- MString out;
- if (begin.line == end.line)
- {
- out += STRPRINTF("%s:%u:%u: %s: %s\n"_fmt,
- begin.filename, begin.line, begin.column, cat, msg);
- out += STRPRINTF("%s\n"_fmt, begin.text);
- out += STRPRINTF("%*c"_fmt, begin.column, '^');
- for (unsigned c = begin.column; c != end.column; ++c)
- out += '~';
- out += '\n';
- }
- else
- {
- out += STRPRINTF("%s:%u:%u: %s: %s\n"_fmt,
- begin.filename, begin.line, begin.column, cat, msg);
- out += STRPRINTF("%s\n"_fmt, begin.text);
- out += STRPRINTF("%*c"_fmt, begin.column, '^');
- for (unsigned c = begin.column; c != begin.text.size(); ++c)
- out += '~';
- out += " ...\n"_s;
- out += STRPRINTF("%s\n"_fmt, end.text);
- for (unsigned c = 0; c != end.column; ++c)
- out += '~';
- out += '\n';
- }
- return AString(out);
- }
-
- void LineSpan::message(ZString cat, ZString msg) const
- {
- FPRINTF(stderr, "%s"_fmt, message_str(cat, msg));
- }
-
LineReader::LineReader(ZString name)
: filename(name), line(0), column(0), rf(name)
{}
@@ -105,6 +38,14 @@ namespace io
: filename(name), line(0), column(0), rf(fd)
{}
+ LineReader::LineReader(read_file_from_string, ZString name, XString content, int startline, FD fd)
+ : filename(name), line(startline-1), column(0), rf(from_string, content, fd)
+ {}
+
+ LineReader::LineReader(read_file_from_string, ZString name, LString content, int startline, FD fd)
+ : filename(name), line(startline-1), column(0), rf(from_string, content, fd)
+ {}
+
bool LineReader::read_line(Line& l)
{
AString text;
@@ -145,6 +86,38 @@ namespace io
column = 0;
}
+ LineCharReader::LineCharReader(read_file_from_string, ZString name, XString content, int startline, int startcol, FD fd)
+ : LineReader(from_string, name, content, 1, fd)
+ {
+ column = 1; // not 0, not whole line
+ if (rf.is_open())
+ adv();
+ if (!line)
+ column = 0;
+ else
+ {
+ line = startline;
+ column = startcol;
+ line_text = STRPRINTF("%*s"_fmt, static_cast<int>(column-1 + line_text.size()), line_text);
+ }
+ }
+
+ LineCharReader::LineCharReader(read_file_from_string, ZString name, LString content, int startline, int startcol, FD fd)
+ : LineReader(from_string, name, content, 1, fd)
+ {
+ column = 1; // not 0, not whole line
+ if (rf.is_open())
+ adv();
+ if (!line)
+ column = 0;
+ else
+ {
+ line = startline;
+ column = startcol;
+ line_text = STRPRINTF("%*s"_fmt, static_cast<int>(column-1 + line_text.size()), line_text);
+ }
+ }
+
bool LineCharReader::get(LineChar& c)
{
if (!column)
diff --git a/src/io/line.hpp b/src/io/line.hpp
index 5572e98..c94eeb9 100644
--- a/src/io/line.hpp
+++ b/src/io/line.hpp
@@ -21,68 +21,15 @@
#include "fwd.hpp"
#include "../strings/rstring.hpp"
-#include "../strings/zstring.hpp"
-#include "../strings/literal.hpp"
#include "read.hpp"
+#include "span.hpp"
namespace tmwa
{
namespace io
{
- // TODO split this out
- struct Line
- {
- RString text;
-
- RString filename;
- // 1-based
- uint16_t line, column;
-
- AString message_str(ZString cat, ZString msg) const;
- AString note_str(ZString msg) const { return message_str("note"_s, msg); }
- AString warning_str(ZString msg) const { return message_str("warning"_s, msg); }
- AString error_str(ZString msg) const { return message_str("error"_s, msg); }
- void message(ZString cat, ZString msg) const;
- void note(ZString msg) const { message("note"_s, msg); }
- void warning(ZString msg) const { message("warning"_s, msg); }
- void error(ZString msg) const { message("error"_s, msg); }
- };
-
- // psst, don't tell anyone
- struct LineChar : Line
- {
- char ch()
- {
- size_t c = column - 1;
- if (c == text.size())
- return '\n';
- return text[c];
- }
- };
-
- struct LineSpan
- {
- LineChar begin, end;
-
- AString message_str(ZString cat, ZString msg) const;
- AString note_str(ZString msg) const { return message_str("note"_s, msg); }
- AString warning_str(ZString msg) const { return message_str("warning"_s, msg); }
- AString error_str(ZString msg) const { return message_str("error"_s, msg); }
- void message(ZString cat, ZString msg) const;
- void note(ZString msg) const { message("note"_s, msg); }
- void warning(ZString msg) const { message("warning"_s, msg); }
- void error(ZString msg) const { message("error"_s, msg); }
- };
-
- template<class T>
- struct Spanned
- {
- T data;
- LineSpan span;
- };
-
class LineReader
{
protected:
@@ -96,6 +43,8 @@ namespace io
LineReader& operator = (LineReader&&) = delete;
// needed for unit tests
LineReader(ZString name, FD fd);
+ LineReader(read_file_from_string, ZString name, XString content, int startline=1, FD fd=FD());
+ LineReader(read_file_from_string, ZString name, LString content, int startline=1, FD fd=FD());
bool read_line(Line& l);
bool is_open();
@@ -110,6 +59,8 @@ namespace io
LineCharReader(LineCharReader&&) = delete;
LineCharReader& operator = (LineCharReader&&) = delete;
LineCharReader(ZString name, FD fd);
+ LineCharReader(read_file_from_string, ZString name, XString content, int startline=1, int startcol=1, FD fd=FD());
+ LineCharReader(read_file_from_string, ZString name, LString content, int startline=1, int startcol=1, FD fd=FD());
bool get(LineChar& c);
void adv();
diff --git a/src/io/line_test.cpp b/src/io/line_test.cpp
index 46e7b57..582ee81 100644
--- a/src/io/line_test.cpp
+++ b/src/io/line_test.cpp
@@ -130,6 +130,20 @@ TEST(io, line5)
EXPECT_EQ(hi.column, 0);
EXPECT_FALSE(lr.read_line(hi));
}
+TEST(io, line1text)
+{
+ io::LineReader lr(io::from_string, "<string1text>"_s, "Hello\nWorld"_s, 2);
+ io::Line hi;
+ EXPECT_TRUE(lr.read_line(hi));
+ EXPECT_EQ(hi.text, "Hello"_s);
+ EXPECT_EQ(hi.line, 2);
+ EXPECT_EQ(hi.column, 0);
+ EXPECT_TRUE(lr.read_line(hi));
+ EXPECT_EQ(hi.text, "World"_s);
+ EXPECT_EQ(hi.line, 3);
+ EXPECT_EQ(hi.column, 0);
+ EXPECT_FALSE(lr.read_line(hi));
+}
TEST(io, linechar1)
{
@@ -382,6 +396,42 @@ TEST(io, linechar5)
lr.adv();
EXPECT_FALSE(lr.get(c));
}
+TEST(io, linechar1text)
+{
+ io::LineCharReader lr(io::from_string, "<stringchar1text>"_s, "Hi\nWu\n"_s, 2, 3);
+ io::LineChar c;
+ EXPECT_TRUE(lr.get(c));
+ EXPECT_EQ(c.ch(), 'H');
+ EXPECT_EQ(c.line, 2);
+ EXPECT_EQ(c.column, 3);
+ lr.adv();
+ EXPECT_TRUE(lr.get(c));
+ EXPECT_EQ(c.ch(), 'i');
+ EXPECT_EQ(c.line, 2);
+ EXPECT_EQ(c.column, 4);
+ lr.adv();
+ EXPECT_TRUE(lr.get(c));
+ EXPECT_EQ(c.ch(), '\n');
+ EXPECT_EQ(c.line, 2);
+ EXPECT_EQ(c.column, 5);
+ lr.adv();
+ EXPECT_TRUE(lr.get(c));
+ EXPECT_EQ(c.ch(), 'W');
+ EXPECT_EQ(c.line, 3);
+ EXPECT_EQ(c.column, 1);
+ lr.adv();
+ EXPECT_TRUE(lr.get(c));
+ EXPECT_EQ(c.ch(), 'u');
+ EXPECT_EQ(c.line, 3);
+ EXPECT_EQ(c.column, 2);
+ lr.adv();
+ EXPECT_TRUE(lr.get(c));
+ EXPECT_EQ(c.ch(), '\n');
+ EXPECT_EQ(c.line, 3);
+ EXPECT_EQ(c.column, 3);
+ lr.adv();
+ EXPECT_FALSE(lr.get(c));
+}
TEST(io, linespan)
{
diff --git a/src/io/read.cpp b/src/io/read.cpp
index 30620a1..d701c7f 100644
--- a/src/io/read.cpp
+++ b/src/io/read.cpp
@@ -1,7 +1,7 @@
#include "read.hpp"
// io/read.cpp - Input from files
//
-// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
+// Copyright © 2013-2014 Ben Longbons <b.r.longbons@gmail.com>
//
// This file is part of The Mana World (Athena server)
//
@@ -48,6 +48,32 @@ namespace io
: fd(dir.open_fd(name, O_RDONLY | O_CLOEXEC)), start(0), end(0)
{
}
+ ReadFile::ReadFile(read_file_from_string, XString content, FD f)
+ : fd(f), start(0), end(), extra()
+ {
+ if (content.size() <= 4096)
+ {
+ end = content.size();
+ auto z = std::copy(content.begin(), content.end(), buf);
+ // only for debug sanity
+ std::fill(z, std::end(buf), 0);
+ return;
+ }
+ auto base = content.base();
+ if (!base)
+ {
+ extra = content;
+ end = content.size();
+ return;
+ }
+ start = &*content.begin() - &*base->begin();
+ end = &*content.end() - &*base->begin();
+ extra = *base;
+ }
+ ReadFile::ReadFile(read_file_from_string, LString content, FD f)
+ : ReadFile(from_string, RString(content), f)
+ {
+ }
ReadFile::~ReadFile()
{
fd.close();
@@ -56,6 +82,14 @@ namespace io
bool ReadFile::get(char& c)
{
+ if (extra)
+ {
+ c = extra[start];
+ ++start;
+ if (start == end)
+ extra = ""_s;
+ return true;
+ }
if (start == end)
{
if (fd == FD())
@@ -125,7 +159,7 @@ namespace io
bool ReadFile::is_open()
{
- return fd != FD();
+ return fd != FD() || start != end;
}
} // namespace io
} // namespace tmwa
diff --git a/src/io/read.hpp b/src/io/read.hpp
index c1c4882..2e3611b 100644
--- a/src/io/read.hpp
+++ b/src/io/read.hpp
@@ -1,7 +1,7 @@
#pragma once
// io/read.hpp - Input from files.
//
-// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
+// Copyright © 2013-2014 Ben Longbons <b.r.longbons@gmail.com>
//
// This file is part of The Mana World (Athena server)
//
@@ -20,6 +20,8 @@
#include "fwd.hpp"
+#include "../strings/rstring.hpp"
+
#include "dir.hpp"
#include "fd.hpp"
@@ -27,18 +29,28 @@ namespace tmwa
{
namespace io
{
+ enum read_file_from_string
+ {
+ from_string,
+ };
+
+ // TODO - for internal warnings, it would be convenient if this class
+ // didn't exist at all, and instead everything was done with line info.
class ReadFile
{
private:
FD fd;
unsigned short start, end;
char buf[4096];
+ RString extra;
public:
explicit
ReadFile(FD fd);
explicit
ReadFile(ZString name);
ReadFile(const DirFd& dir, ZString name);
+ ReadFile(read_file_from_string, XString content, FD fd=FD());
+ ReadFile(read_file_from_string, LString content, FD fd=FD());
ReadFile& operator = (ReadFile&&) = delete;
ReadFile(ReadFile&&) = delete;
diff --git a/src/io/read_test.cpp b/src/io/read_test.cpp
index e655eb1..22c67c8 100644
--- a/src/io/read_test.cpp
+++ b/src/io/read_test.cpp
@@ -93,4 +93,65 @@ TEST(io, read5)
EXPECT_FALSE(hi);
EXPECT_FALSE(rf.getline(hi));
}
+
+#define S15 "0123456789abcde"_s
+#define S16 "0123456789abcdef"_s
+#define S255 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S15
+#define S256 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16 S16
+#define S4095 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S255
+#define S4096 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256 S256
+
+TEST(io, readstringr)
+{
+ LString tests[] =
+ {
+ S15,
+ S16,
+ S255,
+ S256,
+ S4095,
+ S4096,
+ S4096 S16,
+ };
+ for (RString test : tests)
+ {
+ char buf[test.size() + 1];
+
+ io::ReadFile rf(io::from_string, test);
+ EXPECT_EQ(rf.get(buf, sizeof(buf)), test.size());
+ EXPECT_EQ(test, XString(buf + 0, buf + test.size(), nullptr));
+
+ io::ReadFile rf2(io::from_string, test, string_pipe("\na"_s));
+ EXPECT_EQ(rf2.get(buf, sizeof(buf)), test.size() + 1);
+ EXPECT_EQ(test, XString(buf + 0, buf + test.size(), nullptr));
+ EXPECT_EQ('\n', buf[test.size()]);
+ }
+}
+
+TEST(io, readstringx)
+{
+ LString tests[] =
+ {
+ S15,
+ S16,
+ S255,
+ S256,
+ S4095,
+ S4096,
+ S4096 S16,
+ };
+ for (XString test : tests)
+ {
+ char buf[test.size() + 1];
+
+ io::ReadFile rf(io::from_string, test);
+ EXPECT_EQ(rf.get(buf, sizeof(buf)), test.size());
+ EXPECT_EQ(test, XString(buf + 0, buf + test.size(), nullptr));
+
+ io::ReadFile rf2(io::from_string, test, string_pipe("\na"_s));
+ EXPECT_EQ(rf2.get(buf, sizeof(buf)), test.size() + 1);
+ EXPECT_EQ(test, XString(buf + 0, buf + test.size(), nullptr));
+ EXPECT_EQ('\n', buf[test.size()]);
+ }
+}
} // namespace tmwa
diff --git a/src/io/span.cpp b/src/io/span.cpp
new file mode 100644
index 0000000..f4752f0
--- /dev/null
+++ b/src/io/span.cpp
@@ -0,0 +1,99 @@
+#include "span.hpp"
+// io/span.cpp - Tracking info about input
+//
+// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// 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 3 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, see <http://www.gnu.org/licenses/>.
+
+#include "../strings/astring.hpp"
+#include "../strings/mstring.hpp"
+#include "../strings/zstring.hpp"
+
+#include "cxxstdio.hpp"
+
+#include "../poison.hpp"
+
+
+namespace tmwa
+{
+namespace io
+{
+ AString Line::message_str(ZString cat, ZString msg) const
+ {
+ MString out;
+ if (column)
+ out += STRPRINTF("%s:%u:%u: %s: %s\n"_fmt,
+ filename, line, column, cat, msg);
+ else
+ out += STRPRINTF("%s:%u: %s: %s\n"_fmt,
+ filename, line, cat, msg);
+ out += STRPRINTF("%s\n"_fmt, text);
+ out += STRPRINTF("%*c\n"_fmt, column, '^');
+ return AString(out);
+ }
+
+ void Line::message(ZString cat, ZString msg) const
+ {
+ if (column)
+ FPRINTF(stderr, "%s:%u:%u: %s: %s\n"_fmt,
+ filename, line, column, cat, msg);
+ else
+ FPRINTF(stderr, "%s:%u: %s: %s\n"_fmt,
+ filename, line, cat, msg);
+ FPRINTF(stderr, "%s\n"_fmt, text);
+ FPRINTF(stderr, "%*c\n"_fmt, column, '^');
+ }
+
+ AString LineSpan::message_str(ZString cat, ZString msg) const
+ {
+ assert (begin.column);
+ assert (end.column);
+ assert (begin.line < end.line || begin.column <= end.column);
+
+ MString out;
+ if (begin.line == end.line)
+ {
+ out += STRPRINTF("%s:%u:%u: %s: %s\n"_fmt,
+ begin.filename, begin.line, begin.column, cat, msg);
+ out += STRPRINTF("%s\n"_fmt, begin.text);
+ out += STRPRINTF("%*c"_fmt, begin.column, '^');
+ for (unsigned c = begin.column; c != end.column; ++c)
+ out += '~';
+ out += '\n';
+ }
+ else
+ {
+ out += STRPRINTF("%s:%u:%u: %s: %s\n"_fmt,
+ begin.filename, begin.line, begin.column, cat, msg);
+ out += STRPRINTF("%s\n"_fmt, begin.text);
+ out += STRPRINTF("%*c"_fmt, begin.column, '^');
+ for (unsigned c = begin.column; c != begin.text.size(); ++c)
+ out += '~';
+ out += " ...\n"_s;
+ out += STRPRINTF("%s\n"_fmt, end.text);
+ for (unsigned c = 0; c != end.column; ++c)
+ out += '~';
+ out += '\n';
+ }
+ return AString(out);
+ }
+
+ void LineSpan::message(ZString cat, ZString msg) const
+ {
+ FPRINTF(stderr, "%s"_fmt, message_str(cat, msg));
+ }
+} // namespace io
+} // namespace tmwa
diff --git a/src/io/span.hpp b/src/io/span.hpp
new file mode 100644
index 0000000..e474a7a
--- /dev/null
+++ b/src/io/span.hpp
@@ -0,0 +1,90 @@
+#pragma once
+// io/span.hpp - Tracking info about input
+//
+// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// 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 3 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, see <http://www.gnu.org/licenses/>.
+
+#include "fwd.hpp"
+
+#include "../strings/rstring.hpp"
+#include "../strings/zstring.hpp"
+#include "../strings/literal.hpp"
+
+
+namespace tmwa
+{
+namespace io
+{
+ // TODO split this out
+ struct Line
+ {
+ RString text;
+
+ RString filename;
+ // 1-based
+ uint16_t line, column;
+
+ AString message_str(ZString cat, ZString msg) const;
+ AString note_str(ZString msg) const { return message_str("note"_s, msg); }
+ AString warning_str(ZString msg) const { return message_str("warning"_s, msg); }
+ AString error_str(ZString msg) const { return message_str("error"_s, msg); }
+ void message(ZString cat, ZString msg) const;
+ void note(ZString msg) const { message("note"_s, msg); }
+ void warning(ZString msg) const { message("warning"_s, msg); }
+ void error(ZString msg) const { message("error"_s, msg); }
+ };
+
+ // psst, don't tell anyone
+ struct LineChar : Line
+ {
+ char ch()
+ {
+ size_t c = column - 1;
+ if (c == text.size())
+ return '\n';
+ return text[c];
+ }
+ };
+
+ struct LineSpan
+ {
+ LineChar begin, end;
+
+ AString message_str(ZString cat, ZString msg) const;
+ AString note_str(ZString msg) const { return message_str("note"_s, msg); }
+ AString warning_str(ZString msg) const { return message_str("warning"_s, msg); }
+ AString error_str(ZString msg) const { return message_str("error"_s, msg); }
+ void message(ZString cat, ZString msg) const;
+ void note(ZString msg) const { message("note"_s, msg); }
+ void warning(ZString msg) const { message("warning"_s, msg); }
+ void error(ZString msg) const { message("error"_s, msg); }
+ };
+
+ template<class T>
+ struct Spanned
+ {
+ T data;
+ LineSpan span;
+ };
+
+ template<class T>
+ Spanned<T> respan(LineSpan span, T data)
+ {
+ return Spanned<T>{std::move(data), std::move(span)};
+ }
+} // namespace io
+} // namespace tmwa