Coverage for src / competitive_verifier / oj / languages / nim.py: 28%
72 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-04-26 12:38 +0900
« prev ^ index » next coverage.py v7.13.1, created at 2026-04-26 12:38 +0900
1# Python Version: 3.x
2import functools
3import pathlib
4from collections.abc import Generator
5from logging import getLogger
7from pydantic import BaseModel, Field
9from competitive_verifier.util import read_text_normalized
11from .base import Language, LanguageEnvironment, OjVerifyLanguageConfig
13logger = getLogger(__name__)
15DEFAULT_COMPILE_TO = "cpp"
16DEFAULT_NIM_FLAGS = ["-d:release", "--opt:speed"]
19class OjVerifyNimConfigEnv(BaseModel):
20 compile_to: str | None
21 NIMFLAGS: list[str] | None
24class OjVerifyNimConfig(OjVerifyLanguageConfig):
25 environments: list[OjVerifyNimConfigEnv] = Field(
26 default_factory=list[OjVerifyNimConfigEnv]
27 )
30class NimLanguageEnvironment(LanguageEnvironment):
31 compile_to: str
32 nim_flags: list[str]
34 def __init__(self, *, compile_to: str, nim_flags: list[str]):
35 self.compile_to = compile_to
36 self.nim_flags = nim_flags
38 @property
39 def name(self) -> str:
40 return "Nim"
42 def get_compile_command(
43 self, path: pathlib.Path, *, basedir: pathlib.Path, tempdir: pathlib.Path
44 ) -> list[str]:
45 return [
46 "nim",
47 self.compile_to,
48 "-p:.",
49 f"-o:{tempdir / 'a.out'!s}",
50 f"--nimcache:{tempdir!s}",
51 *self.nim_flags,
52 str(path),
53 ]
55 def get_execute_command(
56 self, path: pathlib.Path, *, basedir: pathlib.Path, tempdir: pathlib.Path
57 ) -> str:
58 return str(tempdir / "a.out")
61def _parse_path(lines: list[str]) -> Generator[str, None, None]:
62 for line in lines:
63 l = line.strip()
64 if l.startswith("include"):
65 yield from l[7:].strip().split(",")
66 elif l.startswith("import"):
67 l = l[6:]
68 i = l.find(" except ")
69 if i >= 0:
70 l = l[:i]
71 yield from l.split(",")
72 elif l.startswith("from"):
73 i = l.find(" import ")
74 if i >= 0:
75 yield l[4 : i - 1]
78def _unquote_path(p: str) -> pathlib.Path:
79 p = p.strip()
80 if p.startswith('"'):
81 p = p[1 : len(p) - 1]
82 else:
83 p += ".nim"
84 return pathlib.Path(p)
87@functools.cache
88def _list_direct_dependencies(
89 path: pathlib.Path,
90 *,
91 basedir: pathlib.Path,
92) -> list[pathlib.Path]:
93 dependencies = [path.resolve()]
94 for item in _parse_path(read_text_normalized(basedir / path).splitlines()):
95 item_ = _unquote_path(item)
96 if item_.exists():
97 dependencies.append(item_)
98 return list(set(dependencies))
101class NimLanguage(Language):
102 config: OjVerifyNimConfig = Field(default_factory=OjVerifyNimConfig)
104 def list_dependencies(
105 self, path: pathlib.Path, *, basedir: pathlib.Path
106 ) -> list[pathlib.Path]:
107 dependencies: list[pathlib.Path] = []
108 visited: set[pathlib.Path] = set()
109 stk = [path.resolve()]
110 while stk:
111 path = stk.pop()
112 if path in visited:
113 continue
114 visited.add(path)
115 for child in _list_direct_dependencies(path, basedir=basedir):
116 dependencies.append(child)
117 stk.append(child)
118 return list(set(dependencies))
120 def list_environments(
121 self, path: pathlib.Path, *, basedir: pathlib.Path
122 ) -> list[NimLanguageEnvironment]:
123 if self.config.environments:
124 return [
125 NimLanguageEnvironment(
126 compile_to=DEFAULT_COMPILE_TO,
127 nim_flags=DEFAULT_NIM_FLAGS,
128 )
129 ]
130 return [
131 NimLanguageEnvironment(
132 compile_to=env.compile_to or DEFAULT_COMPILE_TO,
133 nim_flags=env.NIMFLAGS or DEFAULT_NIM_FLAGS,
134 )
135 for env in self.config.environments
136 ]