11from logging
import Logger, basicConfig, getLogger
12from os
import getenv, environ, pathsep
13from pathlib
import Path
14from typing
import List, Set, Optional
17logger = getLogger(__name__)
23 Expander class is responsible for expanding libraries in the source code.
26 - include (re.Pattern): Regular expression pattern to match #include statements.
27 - lib_paths (List[Path]): List of library paths.
28 - included (Set[Path]): Set of included library file paths.
31 - is_ignored_line(line: str) -> bool: Checks if a line should be ignored during expansion.
32 - find_library(library_name: str) -> Path: Finds the path of a library file.
33 - expand_library(library_file_path: Path) -> List[str]: Expands a library file.
34 - expand(source: str) -> str: Expands libraries in the source code.
38 include = re.compile(
r'#include\s*["<](kyopro_library/[a-z0-9_/]*(|.hpp))[">]\s*')
42 Checks if a line should be ignored during expansion.
45 - line (str): The line to be checked.
48 - bool: True if the line should be ignored, False otherwise.
51 if line.strip() ==
"#pragma once":
55 if line.strip().startswith(
"using std::"):
57 if line.strip()
in [
"#ifdef LOCAL",
"#include \"./debug.hpp\"",
"#else",
"#define debug(...)",
"#define print_line",
"#endif"]
and not HEAD:
59 if line.strip()
in [
"const int INF=1e9+10;",
"const ll INFL=4e18;"]
and not CONST:
69 Initializes an Expander object.
72 - lib_paths (List[Path]): List of library paths.
81 Finds the path of a library file.
84 - library_name (str): The name of the library file.
87 - Path: The path of the library file.
90 - FileNotFoundError: If the library file cannot be found.
94 path = lib_path / library_name
97 logger.error(
"cannot find: {}".
format(library_name))
98 raise FileNotFoundError()
102 Expands a library file.
105 - library_file_path (Path): The path of the library file.
108 - List[str]: The expanded lines of the library file.
111 if library_file_path
in self.
included:
112 logger.info(
"already included: {}".
format(library_file_path.name))
114 self.
included.add(library_file_path)
115 logger.info(
"include: {}".
format(library_file_path.name))
117 library_source = open(str(library_file_path)).read()
120 for line
in library_source.splitlines():
124 line = line.replace(
"../../../../",
"")
125 line = line.replace(
"../../../",
"")
126 line = line.replace(
"../../",
"")
127 line = line.replace(
"../",
"")
147 Expands libraries in the source code.
150 - source (str): The source code to be expanded.
153 - str: The expanded source code.
158 for line
in source.splitlines():
166 if "debug" in line
or "print_line" in line:
173 return "\n".join(result)
176if __name__ ==
"__main__":
178 format=
"%(asctime)s [%(levelname)s] %(message)s",
180 level=getenv(
"LOG_LEVEL",
"INFO"),
182 parser = argparse.ArgumentParser(description=
"Expander")
183 parser.add_argument(
"source", help=
"Source File")
184 parser.add_argument(
"-c",
"--console", action=
"store_true", help=
"Print to Console")
185 parser.add_argument(
"--lib", help=
"Path to Atcoder Library")
186 opts = parser.parse_args()
190 lib_paths.append(Path(opts.lib))
191 if "CPLUS_INCLUDE_PATH" in environ:
193 map(Path, filter(
None, environ[
"CPLUS_INCLUDE_PATH"].split(pathsep)))
195 lib_paths.append(Path.cwd())
197 source = open(opts.source).read()
198 output = expander.expand(source)
203 with open(
"combined.cpp",
"w")
as f:
Expander class is responsible for expanding libraries in the source code.
bool is_ignored_line(self, line)
Checks if a line should be ignored during expansion.
__init__(self, List[Path] lib_paths)
Initializes an Expander object.
str expand(self, str source)
Expands libraries in the source code.
Path find_library(self, str library_name)
Finds the path of a library file.
List[str] expand_library(self, Path library_file_path)
Expands a library file.