mirror of https://github.com/KLayout/klayout.git
WIP: Provide a generic include file expansion mechanism, basic class.
This commit is contained in:
parent
a5d675304c
commit
77a9253273
|
|
@ -8,11 +8,13 @@ DEFINES += MAKE_LYM_LIBRARY
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
gsiDeclLymMacro.cc \
|
gsiDeclLymMacro.cc \
|
||||||
|
lymInclude.cpp \
|
||||||
lymMacroInterpreter.cc \
|
lymMacroInterpreter.cc \
|
||||||
lymMacro.cc \
|
lymMacro.cc \
|
||||||
|
|
||||||
HEADERS = \
|
HEADERS = \
|
||||||
lymCommon.h \
|
lymCommon.h \
|
||||||
|
lymInclude.h \
|
||||||
lymMacroInterpreter.h \
|
lymMacroInterpreter.h \
|
||||||
lymMacro.h \
|
lymMacro.h \
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,189 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "lymInclude.h"
|
||||||
|
|
||||||
|
#include "tlAssert.h"
|
||||||
|
#include "tlString.h"
|
||||||
|
#include "tlFileUtils.h"
|
||||||
|
#include "tlStream.h"
|
||||||
|
#include "tlExpression.h"
|
||||||
|
#include "tlUri.h"
|
||||||
|
|
||||||
|
namespace lym
|
||||||
|
{
|
||||||
|
|
||||||
|
static const char *valid_fn_chars = "@_:,.\\/-+";
|
||||||
|
|
||||||
|
IncludeExpander::IncludeExpander ()
|
||||||
|
{
|
||||||
|
// .. nothing yet ..
|
||||||
|
}
|
||||||
|
|
||||||
|
IncludeExpander
|
||||||
|
IncludeExpander::expand (const std::string &path, std::string &expanded_text)
|
||||||
|
{
|
||||||
|
IncludeExpander ie;
|
||||||
|
int lc = 1;
|
||||||
|
read (path, expanded_text, ie, lc);
|
||||||
|
return ie;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
IncludeExpander::read (const std::string &path, std::string &expanded_text, IncludeExpander &ie, int &line_counter)
|
||||||
|
{
|
||||||
|
ie.m_sections [line_counter] = std::make_pair (path, 1 - line_counter);
|
||||||
|
|
||||||
|
tl::InputStream is (path);
|
||||||
|
tl::TextInputStream text (is);
|
||||||
|
|
||||||
|
int lnum = 0;
|
||||||
|
bool emit_section = false;
|
||||||
|
|
||||||
|
while (! text.at_end ()) {
|
||||||
|
|
||||||
|
std::string l = text.get_line ();
|
||||||
|
++lnum;
|
||||||
|
|
||||||
|
tl::Extractor ex (l.c_str ());
|
||||||
|
if (ex.test ("#") && ex.test ("%include")) {
|
||||||
|
|
||||||
|
std::string include_path = tl::trim (ex.skip ());
|
||||||
|
|
||||||
|
// allow some customization by employing expression interpolation
|
||||||
|
include_path = tl::Eval ().interpolate (include_path);
|
||||||
|
|
||||||
|
// NOTE: by using URI's we can basically read from HTTP etc.
|
||||||
|
tl::URI current_uri (path);
|
||||||
|
tl::URI new_uri (include_path);
|
||||||
|
if (current_uri.scheme ().empty () && new_uri.scheme ().empty ()) {
|
||||||
|
if (! tl::is_absolute (include_path)) {
|
||||||
|
include_path = tl::combine_path (tl::dirname (path), include_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
include_path = current_uri.resolved (new_uri).to_string ();
|
||||||
|
}
|
||||||
|
|
||||||
|
read (include_path, expanded_text, ie, line_counter);
|
||||||
|
|
||||||
|
emit_section = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (emit_section) {
|
||||||
|
emit_section = false;
|
||||||
|
ie.m_sections [line_counter] = std::make_pair (path, lnum - line_counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
expanded_text += l;
|
||||||
|
expanded_text += "\n";
|
||||||
|
++line_counter;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
IncludeExpander::to_string () const
|
||||||
|
{
|
||||||
|
if (m_sections.empty ()) {
|
||||||
|
|
||||||
|
return std::string ();
|
||||||
|
|
||||||
|
} else if (m_sections.size () == 1) {
|
||||||
|
|
||||||
|
tl_assert (m_sections.begin ()->first == 1);
|
||||||
|
tl_assert (m_sections.begin ()->second.second == 0);
|
||||||
|
|
||||||
|
std::string fn = m_sections.begin ()->second.first;
|
||||||
|
return tl::to_word_or_quoted_string (fn, valid_fn_chars);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// "@" indicates a mapping table
|
||||||
|
std::string res ("@");
|
||||||
|
|
||||||
|
for (std::map<int, std::pair<std::string, int> >::const_iterator m = m_sections.begin (); m != m_sections.end (); ++m) {
|
||||||
|
res += tl::to_string (m->first);
|
||||||
|
res += ":";
|
||||||
|
res += tl::to_word_or_quoted_string (m->second.first, valid_fn_chars);
|
||||||
|
res += "*";
|
||||||
|
res += tl::to_string (m->second.second);
|
||||||
|
res += ";";
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IncludeExpander
|
||||||
|
IncludeExpander::from_string (const std::string &s)
|
||||||
|
{
|
||||||
|
IncludeExpander ie;
|
||||||
|
|
||||||
|
tl::Extractor ex (s.c_str ());
|
||||||
|
|
||||||
|
if (ex.test ("@")) {
|
||||||
|
|
||||||
|
while (! ex.at_end ()) {
|
||||||
|
|
||||||
|
int ln = 0;
|
||||||
|
ex.read (ln);
|
||||||
|
|
||||||
|
std::pair<std::string, int> &si = ie.m_sections [ln];
|
||||||
|
|
||||||
|
ex.expect (":");
|
||||||
|
ex.read_word_or_quoted (si.first, valid_fn_chars);
|
||||||
|
ex.expect ("*");
|
||||||
|
ex.read (si.second);
|
||||||
|
|
||||||
|
ex.test (";");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
ex.read_word_or_quoted (ie.m_sections [1].first, valid_fn_chars);
|
||||||
|
ex.expect_end ();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ie;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::string, int>
|
||||||
|
IncludeExpander::translate_to_original (int line_number)
|
||||||
|
{
|
||||||
|
std::map<int, std::pair<std::string, int> >::const_iterator m = m_sections.lower_bound (line_number);
|
||||||
|
if (m != m_sections.begin () && (m == m_sections.end () || m->first > line_number)) {
|
||||||
|
--m;
|
||||||
|
}
|
||||||
|
if (m == m_sections.end ()) {
|
||||||
|
return std::make_pair (std::string (), 0);
|
||||||
|
} else {
|
||||||
|
return std::make_pair (m->second.first, line_number + m->second.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HDR_lymInclude
|
||||||
|
#define HDR_lymInclude
|
||||||
|
|
||||||
|
#include "lymCommon.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace lym
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provide the basic include expansion and file/line mapping mechanism
|
||||||
|
*
|
||||||
|
* The Expander object performs the file expansion and also stores the information
|
||||||
|
* required for translating back file names and line numbers.
|
||||||
|
*
|
||||||
|
* Include expansion happens through a pseudo-comment "# %include ..." which
|
||||||
|
* takes a file path as the argument. File paths are always resolved relative to
|
||||||
|
* the original file.
|
||||||
|
* The file path is expression-interpolated, hence can access environment variables
|
||||||
|
* through $(env("HOME")) for example.
|
||||||
|
*/
|
||||||
|
class LYM_PUBLIC IncludeExpander
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief The default constructor
|
||||||
|
*/
|
||||||
|
IncludeExpander ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides include expansion
|
||||||
|
*
|
||||||
|
* This method will deliver the expanded text and the include expander object.
|
||||||
|
*/
|
||||||
|
static IncludeExpander expand (const std::string &path, std::string &expanded_text);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Serializes the include expander information into a string
|
||||||
|
*
|
||||||
|
* If no include expansion happened, the serialized string will be the original file path.
|
||||||
|
* Otherwise it's a "@"-prefixed string.
|
||||||
|
*/
|
||||||
|
std::string to_string () const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deserializes the include expander information from a string
|
||||||
|
*/
|
||||||
|
static IncludeExpander from_string (const std::string &s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides translation of the expanded text's line number to filename/line number for the original file
|
||||||
|
*/
|
||||||
|
std::pair<std::string, int> translate_to_original (int line_number);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides translation of original file name/line number to included file name/line number
|
||||||
|
*/
|
||||||
|
static std::pair<std::string, int> translate_to_original (const std::string &file, int line_number)
|
||||||
|
{
|
||||||
|
IncludeExpander ie;
|
||||||
|
ie.from_string (file);
|
||||||
|
return ie.translate_to_original (line_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::map<int, std::pair<std::string, int> > m_sections;
|
||||||
|
|
||||||
|
static void read (const std::string &path, std::string &expanded_text, IncludeExpander &ie, int &line_counter);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
KLayout Layout Viewer
|
|
||||||
Copyright (C) 2006-2020 Matthias Koefferlein
|
|
||||||
|
|
||||||
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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "tlUnitTest.h"
|
|
||||||
|
|
||||||
TEST(1)
|
|
||||||
{
|
|
||||||
EXPECT_EQ (1, 1); // avoids a compiler warning because of unreferenced _this
|
|
||||||
|
|
||||||
// TODO: add tests for lym specific things
|
|
||||||
throw tl::CancelException (); // skip this test to indicate that there is nothing yet
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
KLayout Layout Viewer
|
||||||
|
Copyright (C) 2006-2020 Matthias Koefferlein
|
||||||
|
|
||||||
|
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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "tlUnitTest.h"
|
||||||
|
#include "tlFileUtils.h"
|
||||||
|
#include "lymInclude.h"
|
||||||
|
|
||||||
|
TEST(1_simple)
|
||||||
|
{
|
||||||
|
std::string fn = tl::testsrc () + "/testdata/lym/x.txt";
|
||||||
|
|
||||||
|
std::string et;
|
||||||
|
lym::IncludeExpander ie = lym::IncludeExpander::expand (fn, et);
|
||||||
|
EXPECT_EQ (et, "A line\nAnother line\n");
|
||||||
|
EXPECT_EQ (ie.to_string (), fn);
|
||||||
|
EXPECT_EQ (lym::IncludeExpander::from_string (ie.to_string ()).to_string (), ie.to_string ());
|
||||||
|
|
||||||
|
EXPECT_EQ (ie.translate_to_original (2).first, fn);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (2).second, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(2_single_include)
|
||||||
|
{
|
||||||
|
std::string fn = tl::testsrc () + "/testdata/lym/x_inc1.txt";
|
||||||
|
|
||||||
|
std::string et;
|
||||||
|
lym::IncludeExpander ie = lym::IncludeExpander::expand (fn, et);
|
||||||
|
EXPECT_EQ (et, "A line\nincluded.1\nAnother line\n");
|
||||||
|
|
||||||
|
EXPECT_EQ (ie.to_string (), "@1:" + tl::testsrc () + "/testdata/lym/x_inc1.txt*0;2:" + tl::testsrc () + "/testdata/lym/inc1.txt*-1;3:" + tl::testsrc () + "/testdata/lym/x_inc1.txt*0;");
|
||||||
|
EXPECT_EQ (lym::IncludeExpander::from_string (ie.to_string ()).to_string (), ie.to_string ());
|
||||||
|
|
||||||
|
EXPECT_EQ (ie.translate_to_original (1).first, fn);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (1).second, 1);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (2).first, tl::testsrc () + "/testdata/lym/inc1.txt");
|
||||||
|
EXPECT_EQ (ie.translate_to_original (2).second, 1);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (3).first, fn);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (3).second, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(3_multi_include)
|
||||||
|
{
|
||||||
|
std::string fn = tl::testsrc () + "/testdata/lym/x_inc3.txt";
|
||||||
|
|
||||||
|
std::string et;
|
||||||
|
lym::IncludeExpander ie = lym::IncludeExpander::expand (fn, et);
|
||||||
|
EXPECT_EQ (et, "A line\ninclude.3a\nincluded.2a\nincluded.2b\ninclude.3b\nAnother line\n");
|
||||||
|
|
||||||
|
EXPECT_EQ (lym::IncludeExpander::from_string (ie.to_string ()).to_string (), ie.to_string ());
|
||||||
|
|
||||||
|
EXPECT_EQ (ie.translate_to_original (1).first, fn);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (1).second, 1);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (2).first, tl::testsrc () + "/testdata/lym/inc3.txt");
|
||||||
|
EXPECT_EQ (ie.translate_to_original (2).second, 1);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (3).first, tl::testsrc () + "/testdata/lym/inc2.txt");
|
||||||
|
EXPECT_EQ (ie.translate_to_original (3).second, 1);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (5).first, tl::testsrc () + "/testdata/lym/inc3.txt");
|
||||||
|
EXPECT_EQ (ie.translate_to_original (5).second, 3);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (6).first, fn);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (6).second, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(4_multi_include_interpolate)
|
||||||
|
{
|
||||||
|
std::string fn = tl::testsrc () + "/testdata/lym/x_inc3_ip.txt";
|
||||||
|
|
||||||
|
std::string et;
|
||||||
|
lym::IncludeExpander ie = lym::IncludeExpander::expand (fn, et);
|
||||||
|
EXPECT_EQ (et, "A line\ninclude.3a\nincluded.2a\nincluded.2b\ninclude.3b\nAnother line\n");
|
||||||
|
|
||||||
|
EXPECT_EQ (lym::IncludeExpander::from_string (ie.to_string ()).to_string (), ie.to_string ());
|
||||||
|
|
||||||
|
EXPECT_EQ (ie.translate_to_original (1).first, fn);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (1).second, 1);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (2).first, tl::testsrc () + "/testdata/lym/inc3.txt");
|
||||||
|
EXPECT_EQ (ie.translate_to_original (2).second, 1);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (3).first, tl::testsrc () + "/testdata/lym/inc2.txt");
|
||||||
|
EXPECT_EQ (ie.translate_to_original (3).second, 1);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (5).first, tl::testsrc () + "/testdata/lym/inc3.txt");
|
||||||
|
EXPECT_EQ (ie.translate_to_original (5).second, 3);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (6).first, fn);
|
||||||
|
EXPECT_EQ (ie.translate_to_original (6).second, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -7,7 +7,7 @@ TARGET = lym_tests
|
||||||
include($$PWD/../../lib_ut.pri)
|
include($$PWD/../../lib_ut.pri)
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
lymBasicTests.cc \
|
lymIncludeTests.cc
|
||||||
|
|
||||||
INCLUDEPATH += $$LYM_INC $$TL_INC $$GSI_INC
|
INCLUDEPATH += $$LYM_INC $$TL_INC $$GSI_INC
|
||||||
DEPENDPATH += $$LYM_INC $$TL_INC $$GSI_INC
|
DEPENDPATH += $$LYM_INC $$TL_INC $$GSI_INC
|
||||||
|
|
|
||||||
|
|
@ -475,6 +475,7 @@ TextInputStream::get_char ()
|
||||||
return 0;
|
return 0;
|
||||||
} else if (*c != '\r' && *c) {
|
} else if (*c != '\r' && *c) {
|
||||||
if (*c == '\n') {
|
if (*c == '\n') {
|
||||||
|
peek_char (); // sets at_end if there is no more character
|
||||||
++m_next_line;
|
++m_next_line;
|
||||||
}
|
}
|
||||||
return *c;
|
return *c;
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1 @@
|
||||||
|
included.1
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
included.2a
|
||||||
|
included.2b
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
include.3a
|
||||||
|
# %include inc2.txt
|
||||||
|
include.3b
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
A line
|
||||||
|
Another line
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
A line
|
||||||
|
# %include inc1.txt
|
||||||
|
Another line
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
A line
|
||||||
|
# %include inc3.txt
|
||||||
|
Another line
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
A line
|
||||||
|
# %include inc$(1+2).txt
|
||||||
|
Another line
|
||||||
Loading…
Reference in New Issue