Coverage for src / competitive_verifier / oj / verify / languages / nim.py: 28%
73 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-03-05 16:00 +0000
« prev ^ index » next coverage.py v7.13.1, created at 2026-03-05 16:00 +0000
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.oj.verify.models import (
10 Language,
11 LanguageEnvironment,
12 OjVerifyLanguageConfig,
13)
14from competitive_verifier.util import read_text_normalized
16logger = getLogger(__name__)
18DEFAULT_COMPILE_TO = "cpp"
19DEFAULT_NIM_FLAGS = ["-d:release", "--opt:speed"]
22class OjVerifyNimConfigEnv(BaseModel):
23 compile_to: str | None
24 NIMFLAGS: list[str] | None
27class OjVerifyNimConfig(OjVerifyLanguageConfig):
28 environments: list[OjVerifyNimConfigEnv] = Field(
29 default_factory=list[OjVerifyNimConfigEnv]
30 )
33class NimLanguageEnvironment(LanguageEnvironment):
34 compile_to: str
35 nim_flags: list[str]
37 def __init__(self, *, compile_to: str, nim_flags: list[str]):
38 self.compile_to = compile_to
39 self.nim_flags = nim_flags
41 @property
42 def name(self) -> str:
43 return "Nim"
45 def get_compile_command(
46 self, path: pathlib.Path, *, basedir: pathlib.Path, tempdir: pathlib.Path
47 ) -> list[str]:
48 return [
49 "nim",
50 self.compile_to,
51 "-p:.",
52 f"-o:{tempdir / 'a.out'!s}",
53 f"--nimcache:{tempdir!s}",
54 *self.nim_flags,
55 str(path),
56 ]
58 def get_execute_command(
59 self, path: pathlib.Path, *, basedir: pathlib.Path, tempdir: pathlib.Path
60 ) -> str:
61 return str(tempdir / "a.out")
64def _parse_path(lines: list[str]) -> Generator[str, None, None]:
65 for line in lines:
66 l = line.strip()
67 if l.startswith("include"):
68 yield from l[7:].strip().split(",")
69 elif l.startswith("import"):
70 l = l[6:]
71 i = l.find(" except ")
72 if i >= 0:
73 l = l[:i]
74 yield from l.split(",")
75 elif l.startswith("from"):
76 i = l.find(" import ")
77 if i >= 0:
78 yield l[4 : i - 1]
81def _unquote_path(p: str) -> pathlib.Path:
82 p = p.strip()
83 if p.startswith('"'):
84 p = p[1 : len(p) - 1]
85 else:
86 p += ".nim"
87 return pathlib.Path(p)
90@functools.cache
91def _list_direct_dependencies(
92 path: pathlib.Path,
93 *,
94 basedir: pathlib.Path,
95) -> list[pathlib.Path]:
96 dependencies = [path.resolve()]
97 for item in _parse_path(read_text_normalized(basedir / path).splitlines()):
98 item_ = _unquote_path(item)
99 if item_.exists():
100 dependencies.append(item_)
101 return list(set(dependencies))
104class NimLanguage(Language):
105 config: OjVerifyNimConfig
107 def __init__(self, *, config: OjVerifyNimConfig | None):
108 self.config = config or OjVerifyNimConfig()
110 def list_dependencies(
111 self, path: pathlib.Path, *, basedir: pathlib.Path
112 ) -> list[pathlib.Path]:
113 dependencies: list[pathlib.Path] = []
114 visited: set[pathlib.Path] = set()
115 stk = [path.resolve()]
116 while stk:
117 path = stk.pop()
118 if path in visited:
119 continue
120 visited.add(path)
121 for child in _list_direct_dependencies(path, basedir=basedir):
122 dependencies.append(child)
123 stk.append(child)
124 return list(set(dependencies))
126 def list_environments(
127 self, path: pathlib.Path, *, basedir: pathlib.Path
128 ) -> list[NimLanguageEnvironment]:
129 if self.config.environments:
130 return [
131 NimLanguageEnvironment(
132 compile_to=DEFAULT_COMPILE_TO,
133 nim_flags=DEFAULT_NIM_FLAGS,
134 )
135 ]
136 return [
137 NimLanguageEnvironment(
138 compile_to=env.compile_to or DEFAULT_COMPILE_TO,
139 nim_flags=env.NIMFLAGS or DEFAULT_NIM_FLAGS,
140 )
141 for env in self.config.environments
142 ]