code-generation: run ruff
Change-Id: I591247ed56f89feba5daf3cbb94211d72a3ba99c
This commit is contained in:
@@ -0,0 +1 @@
|
||||
# noqa: N999 # consistency with rest of the codebase
|
||||
@@ -1,15 +1,12 @@
|
||||
from typing import List, NamedTuple
|
||||
from typing import NamedTuple
|
||||
|
||||
from frontmatter import Post
|
||||
|
||||
from common import cxx_literal, generate_file, load_data
|
||||
import argparse
|
||||
|
||||
KNOWN_KEYS = {"name", "type", "constructorArgs", "implementation", "impure", "renameInGlobalScope"}
|
||||
|
||||
KNOWN_KEYS = set([
|
||||
'name',
|
||||
'type',
|
||||
'constructorArgs',
|
||||
'implementation',
|
||||
'impure',
|
||||
'renameInGlobalScope',
|
||||
])
|
||||
|
||||
class BuiltinConstant(NamedTuple):
|
||||
name: str
|
||||
@@ -19,75 +16,97 @@ class BuiltinConstant(NamedTuple):
|
||||
rename_in_global_scope: bool
|
||||
documentation: str
|
||||
|
||||
def parse(datum):
|
||||
@classmethod
|
||||
def parse(cls, datum: Post) -> "BuiltinConstant":
|
||||
unknown_keys = set(datum.keys()) - KNOWN_KEYS
|
||||
if unknown_keys:
|
||||
raise Exception('unknown keys', unknown_keys)
|
||||
msg = f"unknown keys: {unknown_keys!r}"
|
||||
raise ValueError(msg)
|
||||
if (constructor_args := datum.get("constructorArgs")) is not None:
|
||||
args = [f"NewValueAs::{datum['type']}"] + constructor_args # type: ignore
|
||||
impl = f"{{{','.join(args)}}}"
|
||||
else:
|
||||
impl = datum["implementation"]
|
||||
|
||||
return BuiltinConstant(
|
||||
name = datum['name'],
|
||||
type = datum['type'],
|
||||
implementation = ('{' + ', '.join([f'NewValueAs::{datum["type"]}', *datum['constructorArgs']]) + '}') if 'constructorArgs' in datum else datum['implementation'],
|
||||
impure = datum.get('impure', False),
|
||||
rename_in_global_scope = datum.get('renameInGlobalScope', True),
|
||||
documentation = datum.content,
|
||||
name=datum["name"], # type: ignore
|
||||
type=datum["type"], # type: ignore
|
||||
implementation=impl,
|
||||
impure=datum.get("impure", False), # type: ignore
|
||||
rename_in_global_scope=datum.get("renameInGlobalScope", True), # type: ignore
|
||||
documentation=datum.content,
|
||||
)
|
||||
|
||||
|
||||
VALUE_TYPES = {
|
||||
'attrs': 'nAttrs',
|
||||
'boolean': 'nBool',
|
||||
'integer': 'nInt',
|
||||
'list': 'nList',
|
||||
'null': 'nNull',
|
||||
'string': 'nString',
|
||||
"attrs": "nAttrs",
|
||||
"boolean": "nBool",
|
||||
"integer": "nInt",
|
||||
"list": "nList",
|
||||
"null": "nNull",
|
||||
"string": "nString",
|
||||
}
|
||||
|
||||
HUMAN_TYPES = {
|
||||
'attrs': 'set',
|
||||
'boolean': 'Boolean',
|
||||
'integer': 'integer',
|
||||
'list': 'list',
|
||||
'null': 'null',
|
||||
'string': 'string',
|
||||
"attrs": "set",
|
||||
"boolean": "Boolean",
|
||||
"integer": "integer",
|
||||
"list": "list",
|
||||
"null": "null",
|
||||
"string": "string",
|
||||
}
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--header', help='Path of the header to generate')
|
||||
ap.add_argument('--docs', help='Path of the documentation file to generate')
|
||||
ap.add_argument('defs', help='Builtin definition files', nargs='+')
|
||||
ap.add_argument("--header", help="Path of the header to generate")
|
||||
ap.add_argument("--docs", help="Path of the documentation file to generate")
|
||||
ap.add_argument("defs", help="Builtin definition files", nargs="+")
|
||||
args = ap.parse_args()
|
||||
|
||||
builtin_constants = load_data(args.defs, BuiltinConstant.parse)
|
||||
|
||||
generate_file(args.header, builtin_constants, lambda constant:
|
||||
# `builtins` is magic and must come first
|
||||
'' if constant.name == 'builtins' else constant.name,
|
||||
generate_file(
|
||||
args.header,
|
||||
builtin_constants,
|
||||
lambda constant:
|
||||
f'''{'if (!evalSettings.pureEval) ' if constant.impure else ''}{{
|
||||
addConstant({cxx_literal(('__' if constant.rename_in_global_scope else '') + constant.name)}, {constant.implementation}, {{
|
||||
# `builtins` is magic and must come first
|
||||
"" if constant.name == "builtins" else constant.name,
|
||||
lambda constant: f"""{"if (!evalSettings.pureEval) " if constant.impure else ""}{{
|
||||
addConstant({cxx_literal(("__" if constant.rename_in_global_scope else "") + constant.name)}, {constant.implementation}, {{
|
||||
.type = {VALUE_TYPES[constant.type]},
|
||||
.doc = {cxx_literal(constant.documentation)},
|
||||
.impureOnly = {cxx_literal(constant.impure)},
|
||||
}});
|
||||
}}
|
||||
''')
|
||||
generate_file(args.docs, builtin_constants, lambda constant: constant.name, lambda constant:
|
||||
f'''<dt id="builtins-{constant.name}">
|
||||
""",
|
||||
)
|
||||
generate_file(
|
||||
args.docs,
|
||||
builtin_constants,
|
||||
lambda constant: constant.name,
|
||||
lambda constant: f"""<dt id="builtins-{constant.name}">
|
||||
<a href="#builtins-{constant.name}"><code>{constant.name}</code></a> ({HUMAN_TYPES[constant.type]})
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
{constant.documentation}
|
||||
|
||||
''' + ('''> **Note**
|
||||
"""
|
||||
+ (
|
||||
"""> **Note**
|
||||
>
|
||||
> Not available in [pure evaluation mode](@docroot@/command-ref/conf-file.md#conf-pure-eval).
|
||||
|
||||
''' if constant.impure else '') + '''</dd>
|
||||
"""
|
||||
if constant.impure
|
||||
else ""
|
||||
)
|
||||
+ """</dd>
|
||||
|
||||
''')
|
||||
""",
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1,61 +1,71 @@
|
||||
from typing import List, NamedTuple, Optional
|
||||
from typing import NamedTuple
|
||||
|
||||
from frontmatter import Post
|
||||
|
||||
from build_experimental_features import ExperimentalFeature
|
||||
from common import cxx_literal, generate_file, load_data
|
||||
import argparse
|
||||
|
||||
KNOWN_KEYS = {"name", "implementation", "renameInGlobalScope", "args", "experimentalFeature"}
|
||||
|
||||
KNOWN_KEYS = set([
|
||||
'name',
|
||||
'implementation',
|
||||
'renameInGlobalScope',
|
||||
'args',
|
||||
'experimentalFeature',
|
||||
])
|
||||
|
||||
class Builtin(NamedTuple):
|
||||
name: str
|
||||
implementation: str
|
||||
rename_in_global_scope: bool
|
||||
args: List[str]
|
||||
experimental_feature: Optional[str]
|
||||
args: list[str]
|
||||
experimental_feature: str | None
|
||||
documentation: str
|
||||
|
||||
def parse(datum):
|
||||
@classmethod
|
||||
def parse(cls, datum: Post) -> "Builtin":
|
||||
unknown_keys = set(datum.keys()) - KNOWN_KEYS
|
||||
if unknown_keys:
|
||||
raise Exception('unknown keys', unknown_keys)
|
||||
msg = f"unknown keys: {unknown_keys!r}"
|
||||
raise ValueError(msg)
|
||||
return Builtin(
|
||||
name = datum['name'],
|
||||
implementation = datum['implementation'] if 'implementation' in datum else f'prim_{datum["name"]}',
|
||||
rename_in_global_scope = datum.get('renameInGlobalScope', True),
|
||||
args = datum['args'],
|
||||
experimental_feature = datum.get('experimentalFeature', None),
|
||||
documentation = datum.content,
|
||||
name=datum["name"], # type: ignore
|
||||
implementation=datum["implementation"]
|
||||
if "implementation" in datum
|
||||
else f"prim_{datum['name']}",
|
||||
rename_in_global_scope=datum.get("renameInGlobalScope", True), # type: ignore
|
||||
args=datum["args"], # type: ignore
|
||||
experimental_feature=datum.get("experimentalFeature", None), # type: ignore
|
||||
documentation=datum.content,
|
||||
)
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--header', help='Path of the header to generate')
|
||||
ap.add_argument('--docs', help='Path of the documentation file to generate')
|
||||
ap.add_argument('--experimental-features', help='Directory containing the experimental feature definitions')
|
||||
ap.add_argument('defs', help='Builtin definition files', nargs='+')
|
||||
ap.add_argument("--header", help="Path of the header to generate")
|
||||
ap.add_argument("--docs", help="Path of the documentation file to generate")
|
||||
ap.add_argument(
|
||||
"--experimental-features", help="Directory containing the experimental feature definitions"
|
||||
)
|
||||
ap.add_argument("defs", help="Builtin definition files", nargs="+")
|
||||
args = ap.parse_args()
|
||||
|
||||
builtins = load_data(args.defs, Builtin.parse)
|
||||
|
||||
experimental_feature_names = set([builtin.experimental_feature for (_, builtin) in builtins])
|
||||
experimental_feature_names = {builtin.experimental_feature for (_, builtin) in builtins}
|
||||
experimental_feature_names.discard(None)
|
||||
experimental_feature_files = [f'{args.experimental_features}/{name}.md' for name in experimental_feature_names]
|
||||
experimental_feature_files = [
|
||||
f"{args.experimental_features}/{name}.md" for name in experimental_feature_names
|
||||
]
|
||||
experimental_features = load_data(experimental_feature_files, ExperimentalFeature.parse)
|
||||
experimental_features = dict(map(lambda path_and_feature:
|
||||
(path_and_feature[1].name, f'Xp::{path_and_feature[1].internal_name}'), experimental_features))
|
||||
experimental_features[None] = 'std::nullopt'
|
||||
experimental_features = {
|
||||
path_and_feature[1].name: f"Xp::{path_and_feature[1].internal_name}"
|
||||
for path_and_feature in experimental_features
|
||||
}
|
||||
experimental_features[None] = "std::nullopt"
|
||||
|
||||
generate_file(args.header, builtins, lambda builtin: builtin.name, lambda builtin:
|
||||
f'''{'' if builtin.experimental_feature is None else f'if (experimentalFeatureSettings.isEnabled({experimental_features[builtin.experimental_feature]})) '}{{
|
||||
generate_file(
|
||||
args.header,
|
||||
builtins,
|
||||
lambda builtin: builtin.name,
|
||||
lambda builtin: f"""{"" if builtin.experimental_feature is None else f"if (experimentalFeatureSettings.isEnabled({experimental_features[builtin.experimental_feature]})) "}{{
|
||||
addPrimOp({{
|
||||
.name = {cxx_literal(('__' if builtin.rename_in_global_scope else '') + builtin.name)},
|
||||
.name = {cxx_literal(("__" if builtin.rename_in_global_scope else "") + builtin.name)},
|
||||
.args = {cxx_literal(builtin.args)},
|
||||
.arity = {len(builtin.args)},
|
||||
.doc = {cxx_literal(builtin.documentation)},
|
||||
@@ -63,20 +73,32 @@ def main():
|
||||
.experimentalFeature = {experimental_features[builtin.experimental_feature]},
|
||||
}});
|
||||
}}
|
||||
''')
|
||||
generate_file(args.docs, builtins, lambda builtin: builtin.name, lambda builtin:
|
||||
f'''<dt id="builtins-{builtin.name}">
|
||||
<a href="#builtins-{builtin.name}"><code>{builtin.name} {' '.join([f'<var>{arg}</var>' for arg in builtin.args])}</code></a>
|
||||
""",
|
||||
)
|
||||
generate_file(
|
||||
args.docs,
|
||||
builtins,
|
||||
lambda builtin: builtin.name,
|
||||
lambda builtin: f"""<dt id="builtins-{builtin.name}">
|
||||
<a href="#builtins-{builtin.name}"><code>{builtin.name} {" ".join([f"<var>{arg}</var>" for arg in builtin.args])}</code></a>
|
||||
</dt>
|
||||
<dd>
|
||||
|
||||
{builtin.documentation}
|
||||
|
||||
''' + (f'''This function is only available if the [{builtin.experimental_feature}](@docroot@/contributing/experimental-features.md#xp-feature-{builtin.experimental_feature}) experimental feature is enabled.
|
||||
"""
|
||||
+ (
|
||||
f"""This function is only available if the [{builtin.experimental_feature}](@docroot@/contributing/experimental-features.md#xp-feature-{builtin.experimental_feature}) experimental feature is enabled.
|
||||
|
||||
''' if builtin.experimental_feature is not None else '') + '''</dd>
|
||||
"""
|
||||
if builtin.experimental_feature is not None
|
||||
else ""
|
||||
)
|
||||
+ """</dd>
|
||||
|
||||
''')
|
||||
""",
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1,58 +1,77 @@
|
||||
from typing import NamedTuple
|
||||
|
||||
from frontmatter import Post
|
||||
|
||||
from common import cxx_literal, generate_file, load_data
|
||||
import argparse
|
||||
|
||||
KNOWN_KEYS = {"name", "internalName"}
|
||||
|
||||
KNOWN_KEYS = set([
|
||||
'name',
|
||||
'internalName',
|
||||
])
|
||||
|
||||
class ExperimentalFeature(NamedTuple):
|
||||
name: str
|
||||
internal_name: str
|
||||
description: str
|
||||
|
||||
def parse(datum):
|
||||
@classmethod
|
||||
def parse(cls, datum: Post) -> "ExperimentalFeature":
|
||||
unknown_keys = set(datum.keys()) - KNOWN_KEYS
|
||||
if unknown_keys:
|
||||
raise ValueError('unknown keys', unknown_keys)
|
||||
msg = f"unknown keys: {unknown_keys!r}"
|
||||
raise ValueError(msg)
|
||||
return ExperimentalFeature(
|
||||
name = datum['name'],
|
||||
internal_name = datum['internalName'],
|
||||
description = datum.content,
|
||||
name=datum["name"], # type: ignore
|
||||
internal_name=datum["internalName"], # type: ignore
|
||||
description=datum.content,
|
||||
)
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--deprecated', action='store_true', help='Generate deprecated features')
|
||||
ap.add_argument('--header', help='Path of the declaration header to generate')
|
||||
ap.add_argument('--impl-header', help='Path of the implementation header to generate')
|
||||
ap.add_argument('--descriptions', help='Path of the description file to generate')
|
||||
ap.add_argument('--shortlist', help='Path of the shortlist file to generate')
|
||||
ap.add_argument('defs', help='Experimental feature definition files', nargs='+')
|
||||
ap.add_argument("--deprecated", action="store_true", help="Generate deprecated features")
|
||||
ap.add_argument("--header", help="Path of the declaration header to generate")
|
||||
ap.add_argument("--impl-header", help="Path of the implementation header to generate")
|
||||
ap.add_argument("--descriptions", help="Path of the description file to generate")
|
||||
ap.add_argument("--shortlist", help="Path of the shortlist file to generate")
|
||||
ap.add_argument("defs", help="Experimental feature definition files", nargs="+")
|
||||
args = ap.parse_args()
|
||||
|
||||
features = load_data(args.defs, ExperimentalFeature.parse)
|
||||
|
||||
generate_file(args.header, features, lambda feature: feature.name, lambda feature:
|
||||
f' {feature.internal_name},\n')
|
||||
generate_file(args.impl_header, features, lambda feature: feature.name, lambda feature:
|
||||
f''' {{
|
||||
generate_file(
|
||||
args.header,
|
||||
features,
|
||||
lambda feature: feature.name,
|
||||
lambda feature: f" {feature.internal_name},\n",
|
||||
)
|
||||
generate_file(
|
||||
args.impl_header,
|
||||
features,
|
||||
lambda feature: feature.name,
|
||||
lambda feature: f""" {{
|
||||
.tag = {"Dep" if args.deprecated else "Xp"}::{feature.internal_name},
|
||||
.name = {cxx_literal(feature.name)},
|
||||
.description = {cxx_literal(feature.description)},
|
||||
}},
|
||||
''')
|
||||
generate_file(args.descriptions, features, lambda feature: feature.name, lambda feature:
|
||||
f'''## [`{feature.name}`]{{#{"dp" if args.deprecated else "xp"}-feature-{feature.name}}}
|
||||
""",
|
||||
)
|
||||
generate_file(
|
||||
args.descriptions,
|
||||
features,
|
||||
lambda feature: feature.name,
|
||||
lambda feature: f"""## [`{feature.name}`]{{#{"dp" if args.deprecated else "xp"}-feature-{feature.name}}}
|
||||
|
||||
{feature.description}
|
||||
|
||||
''')
|
||||
generate_file(args.shortlist, features, lambda feature: feature.name, lambda feature:
|
||||
f' - [`{feature.name}`](@docroot@/contributing/{"deprecated" if args.deprecated else "experimental"}-features.md#{"dp" if args.deprecated else "xp"}-feature-{feature.name})\n')
|
||||
""",
|
||||
)
|
||||
generate_file(
|
||||
args.shortlist,
|
||||
features,
|
||||
lambda feature: feature.name,
|
||||
lambda feature: f" - [`{feature.name}`](@docroot@/contributing/{'deprecated' if args.deprecated else 'experimental'}-features.md#{'dp' if args.deprecated else 'xp'}-feature-{feature.name})\n",
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1,101 +1,121 @@
|
||||
from typing import List, NamedTuple, Optional
|
||||
from typing import NamedTuple, Any
|
||||
|
||||
from frontmatter import Post
|
||||
|
||||
from build_experimental_features import ExperimentalFeature
|
||||
from common import cxx_literal, generate_file, load_data
|
||||
import argparse
|
||||
|
||||
KNOWN_KEYS = {
|
||||
"name",
|
||||
"internalName",
|
||||
"platforms",
|
||||
"type",
|
||||
"settingType",
|
||||
"default",
|
||||
"defaultExpr",
|
||||
"defaultText",
|
||||
"aliases",
|
||||
"experimentalFeature",
|
||||
"deprecated",
|
||||
}
|
||||
|
||||
KNOWN_KEYS = set([
|
||||
'name',
|
||||
'internalName',
|
||||
'platforms',
|
||||
'type',
|
||||
'settingType',
|
||||
'default',
|
||||
'defaultExpr',
|
||||
'defaultText',
|
||||
'aliases',
|
||||
'experimentalFeature',
|
||||
'deprecated',
|
||||
])
|
||||
|
||||
class Setting(NamedTuple):
|
||||
name: str
|
||||
internal_name: str
|
||||
description: str
|
||||
platforms: Optional[List[str]]
|
||||
platforms: list[str] | None
|
||||
setting_type: str
|
||||
default_expr: str
|
||||
default_text: str
|
||||
aliases: List[str]
|
||||
experimental_feature: Optional[str]
|
||||
aliases: list[str]
|
||||
experimental_feature: str | None
|
||||
deprecated: bool
|
||||
|
||||
def parse(datum):
|
||||
@classmethod
|
||||
def parse(cls, datum: Post) -> "Setting":
|
||||
unknown_keys = set(datum.keys()) - KNOWN_KEYS
|
||||
if unknown_keys:
|
||||
raise ValueError('unknown keys', unknown_keys)
|
||||
default_text = f'`{nix_conf_literal(datum["default"])}`' if 'default' in datum else datum['defaultText']
|
||||
if default_text == '``':
|
||||
default_text = '*empty*'
|
||||
msg = f"unknown keys: {unknown_keys!r}"
|
||||
raise ValueError(msg)
|
||||
default_text = (
|
||||
f"`{nix_conf_literal(datum['default'])}`"
|
||||
if "default" in datum
|
||||
else datum["defaultText"]
|
||||
)
|
||||
if default_text == "``":
|
||||
default_text = "*empty*"
|
||||
return Setting(
|
||||
name = datum['name'],
|
||||
internal_name = datum['internalName'],
|
||||
description = datum.content,
|
||||
platforms = datum.get('platforms', None),
|
||||
setting_type = f'Setting<{datum["type"]}>' if 'type' in datum else datum['settingType'],
|
||||
default_expr = cxx_literal(datum['default']) if 'default' in datum else datum['defaultExpr'],
|
||||
default_text = default_text,
|
||||
aliases = datum.get('aliases', []),
|
||||
experimental_feature = datum.get('experimentalFeature', None),
|
||||
deprecated = datum.get('deprecated', False),
|
||||
name=datum["name"], # type: ignore
|
||||
internal_name=datum["internalName"], # type: ignore
|
||||
description=datum.content,
|
||||
platforms=datum.get("platforms", None), # type: ignore
|
||||
setting_type=f"Setting<{datum['type']}>" if "type" in datum else datum["settingType"],
|
||||
default_expr=cxx_literal(datum["default"])
|
||||
if "default" in datum
|
||||
else datum["defaultExpr"],
|
||||
default_text=default_text,
|
||||
aliases=datum.get("aliases", []), # type: ignore
|
||||
experimental_feature=datum.get("experimentalFeature", None), # type: ignore
|
||||
deprecated=datum.get("deprecated", False), # type: ignore
|
||||
)
|
||||
|
||||
platform_names = {
|
||||
'darwin': 'Darwin',
|
||||
'linux': 'Linux',
|
||||
}
|
||||
|
||||
def nix_conf_literal(v):
|
||||
platform_names = {"darwin": "Darwin", "linux": "Linux"}
|
||||
|
||||
|
||||
def nix_conf_literal(v: Any) -> str:
|
||||
if v is None:
|
||||
return ''
|
||||
elif isinstance(v, bool) and v == False: # 0 == False
|
||||
return 'false'
|
||||
elif isinstance(v, bool) and v == True: # 1 == True
|
||||
return 'true'
|
||||
elif isinstance(v, int):
|
||||
return ""
|
||||
if v is False:
|
||||
return "false"
|
||||
if v is True:
|
||||
return "true"
|
||||
if isinstance(v, int):
|
||||
return str(v)
|
||||
elif isinstance(v, str):
|
||||
if isinstance(v, str):
|
||||
return v
|
||||
elif isinstance(v, list):
|
||||
return ' '.join([nix_conf_literal(item) for item in v])
|
||||
else:
|
||||
raise NotImplementedError(f'Cannot represent {repr(v)} in nix.conf')
|
||||
if isinstance(v, list):
|
||||
return " ".join([nix_conf_literal(item) for item in v])
|
||||
msg = f"Cannot represent {v!r} in nix.conf"
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
|
||||
def indent(prefix: str, body: str) -> str:
|
||||
return "".join(["\n" if not line else f"{prefix}{line}\n" for line in body.split("\n")])
|
||||
|
||||
def indent(prefix, body):
|
||||
return ''.join(['\n' if line == '' else f'{prefix}{line}\n' for line in body.split('\n')])
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument('--kernel', help='Name of the kernel Lix will run on')
|
||||
ap.add_argument('--header', help='Path of the header to generate')
|
||||
ap.add_argument('--docs', help='Path of the documentation file to generate')
|
||||
ap.add_argument('--experimental-features', help='Directory containing the experimental feature definitions')
|
||||
ap.add_argument('defs', help='Setting definition files', nargs='+')
|
||||
ap.add_argument("--kernel", help="Name of the kernel Lix will run on")
|
||||
ap.add_argument("--header", help="Path of the header to generate")
|
||||
ap.add_argument("--docs", help="Path of the documentation file to generate")
|
||||
ap.add_argument(
|
||||
"--experimental-features", help="Directory containing the experimental feature definitions"
|
||||
)
|
||||
ap.add_argument("defs", help="Setting definition files", nargs="+")
|
||||
args = ap.parse_args()
|
||||
|
||||
settings = load_data(args.defs, Setting.parse)
|
||||
|
||||
experimental_feature_names = set([setting.experimental_feature for (_, setting) in settings])
|
||||
experimental_feature_names = {setting.experimental_feature for (_, setting) in settings}
|
||||
experimental_feature_names.discard(None)
|
||||
experimental_feature_files = [f'{args.experimental_features}/{name}.md' for name in experimental_feature_names]
|
||||
experimental_feature_files = [
|
||||
f"{args.experimental_features}/{name}.md" for name in experimental_feature_names
|
||||
]
|
||||
experimental_features = load_data(experimental_feature_files, ExperimentalFeature.parse)
|
||||
experimental_features = dict(map(lambda path_and_feature:
|
||||
(path_and_feature[1].name, f'Xp::{path_and_feature[1].internal_name}'), experimental_features))
|
||||
experimental_features[None] = 'std::nullopt'
|
||||
experimental_features = {
|
||||
path_and_feature[1].name: f"Xp::{path_and_feature[1].internal_name}"
|
||||
for path_and_feature in experimental_features
|
||||
}
|
||||
experimental_features[None] = "std::nullopt"
|
||||
|
||||
generate_file(args.header, settings, lambda setting: setting.name, lambda setting:
|
||||
f'''{setting.setting_type} {setting.internal_name} {{
|
||||
generate_file(
|
||||
args.header,
|
||||
settings,
|
||||
lambda setting: setting.name,
|
||||
lambda setting: f"""{setting.setting_type} {setting.internal_name} {{
|
||||
this,
|
||||
{setting.default_expr},
|
||||
{cxx_literal(setting.name)},
|
||||
@@ -106,15 +126,28 @@ def main():
|
||||
{cxx_literal(setting.deprecated)}
|
||||
}};
|
||||
|
||||
''' if setting.platforms is None or args.kernel in setting.platforms else '')
|
||||
generate_file(args.docs, settings, lambda setting: setting.name, lambda setting:
|
||||
f'''- <span id="conf-{setting.name}">[`{setting.name}`](#conf-{setting.name})</span>
|
||||
"""
|
||||
if setting.platforms is None or args.kernel in setting.platforms
|
||||
else "",
|
||||
)
|
||||
generate_file(
|
||||
args.docs,
|
||||
settings,
|
||||
lambda setting: setting.name,
|
||||
lambda setting: f"""- <span id="conf-{setting.name}">[`{setting.name}`](#conf-{setting.name})</span>
|
||||
|
||||
{indent(" ", setting.description)}
|
||||
''' + (f''' > **Note**
|
||||
> This setting is only available on {', '.join([platform_names[platform] for platform in setting.platforms])} systems.
|
||||
"""
|
||||
+ (
|
||||
f""" > **Note**
|
||||
> This setting is only available on {", ".join([platform_names[platform] for platform in setting.platforms])} systems.
|
||||
|
||||
''' if setting.platforms is not None else '') + (f''' > **Warning**
|
||||
"""
|
||||
if setting.platforms is not None
|
||||
else ""
|
||||
)
|
||||
+ (
|
||||
f""" > **Warning**
|
||||
> This setting is part of an
|
||||
> [experimental feature](@docroot@/contributing/experimental-features.md).
|
||||
|
||||
@@ -128,14 +161,30 @@ def main():
|
||||
{setting.name} = ...
|
||||
```
|
||||
|
||||
''' if setting.experimental_feature is not None else '') + (''' > **Warning**
|
||||
"""
|
||||
if setting.experimental_feature is not None
|
||||
else ""
|
||||
)
|
||||
+ (
|
||||
""" > **Warning**
|
||||
> This setting is deprecated and will be removed in a future version of Lix.
|
||||
|
||||
''' if setting.deprecated else '') + f''' **Default:** {setting.default_text}
|
||||
"""
|
||||
if setting.deprecated
|
||||
else ""
|
||||
)
|
||||
+ f""" **Default:** {setting.default_text}
|
||||
|
||||
''' + (f''' **Deprecated alias:** {', '.join([f'`{item}`' for item in setting.aliases])}
|
||||
"""
|
||||
+ (
|
||||
f""" **Deprecated alias:** {", ".join([f"`{item}`" for item in setting.aliases])}
|
||||
|
||||
''' if setting.aliases != [] else ''))
|
||||
"""
|
||||
if setting.aliases != []
|
||||
else ""
|
||||
),
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!@python@
|
||||
# ruff: noqa: SIM112 # ignore lowercase env variable names for capnpc as we have them in lower case as arguments
|
||||
|
||||
import argparse
|
||||
import capnp
|
||||
@@ -7,58 +8,61 @@ import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
if lang := os.environ.get('lix_capnp_lang'):
|
||||
outputs = os.environ['lix_capnp_outputs'].split()
|
||||
old_cwd = os.environ['lix_capnp_old_cwd']
|
||||
schema = capnp.load('@capnp_include@/capnp/schema.capnp', imports=['@capnp_include@'])
|
||||
if lang := os.environ.get("lix_capnp_lang"):
|
||||
outputs = os.environ["lix_capnp_outputs"].split()
|
||||
old_cwd = os.environ["lix_capnp_old_cwd"]
|
||||
schema = capnp.load("@capnp_include@/capnp/schema.capnp", imports=["@capnp_include@"])
|
||||
request = schema.CodeGeneratorRequest.read(sys.stdin)
|
||||
|
||||
subprocess.run([lang], input=request.as_builder().to_bytes()).check_returncode()
|
||||
|
||||
base_dir = os.getcwd()
|
||||
base_dir = Path.cwd()
|
||||
os.chdir(old_cwd)
|
||||
|
||||
include = [ str(Path(p).resolve()) for p in os.environ['lix_capnp_include'].split(':') ]
|
||||
include = [str(Path(p).resolve()) for p in os.environ["lix_capnp_include"].split(":")]
|
||||
|
||||
if depfile := os.environ['lix_capnp_depfile']:
|
||||
if depfile := os.environ["lix_capnp_depfile"]:
|
||||
deps = ""
|
||||
for input in request.requestedFiles:
|
||||
deps += " ".join(f"{input.filename}.{o}" for o in outputs)
|
||||
for input_file in request.requestedFiles:
|
||||
deps += " ".join(f"{input_file.filename}.{o}" for o in outputs)
|
||||
deps += ":"
|
||||
for dep in input.imports:
|
||||
for dep in input_file.imports:
|
||||
if dep.name.startswith("/"):
|
||||
for candidate in (Path(i + dep.name) for i in include):
|
||||
if candidate.exists():
|
||||
deps += " " + str(candidate)
|
||||
break
|
||||
else:
|
||||
raise RuntimeError("not handling relative includes")
|
||||
msg = "not handling relative includes"
|
||||
raise RuntimeError(msg)
|
||||
deps += "\n\n"
|
||||
Path(depfile).write_text(deps)
|
||||
else:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--language')
|
||||
parser.add_argument('--outdir')
|
||||
parser.add_argument('--src-prefix')
|
||||
parser.add_argument('--depfile', default="")
|
||||
parser.add_argument('-I', '--include', action='append', default=['@capnp_include@'])
|
||||
parser.add_argument('inputs', nargs='+')
|
||||
parser.add_argument("--language")
|
||||
parser.add_argument("--outdir")
|
||||
parser.add_argument("--src-prefix")
|
||||
parser.add_argument("--depfile", default="")
|
||||
parser.add_argument("-I", "--include", action="append", default=["@capnp_include@"])
|
||||
parser.add_argument("inputs", nargs="+")
|
||||
args = parser.parse_args()
|
||||
|
||||
for infile in args.inputs:
|
||||
os.environ['lix_capnp_lang'] = f"capnpc-{args.language}"
|
||||
os.environ['lix_capnp_include'] = ':'.join(args.include)
|
||||
os.environ['lix_capnp_depfile'] = args.depfile
|
||||
os.environ['lix_capnp_old_cwd'] = os.getcwd()
|
||||
os.environ["lix_capnp_lang"] = f"capnpc-{args.language}"
|
||||
os.environ["lix_capnp_include"] = ":".join(args.include)
|
||||
os.environ["lix_capnp_depfile"] = args.depfile
|
||||
os.environ["lix_capnp_old_cwd"] = str(Path.cwd())
|
||||
if args.language == "c++":
|
||||
os.environ['lix_capnp_outputs'] = "c++ h"
|
||||
os.environ["lix_capnp_outputs"] = "c++ h"
|
||||
else:
|
||||
raise RuntimeError("unknown language " + args.language)
|
||||
subprocess.run([
|
||||
'@capnp@',
|
||||
'compile',
|
||||
f'-o{sys.argv[0]}:{args.outdir}',
|
||||
f'--src-prefix={args.src_prefix}',
|
||||
subprocess.run(
|
||||
[
|
||||
"@capnp@",
|
||||
"compile",
|
||||
f"-o{sys.argv[0]}:{args.outdir}",
|
||||
f"--src-prefix={args.src_prefix}",
|
||||
*(f"-I{i}" for i in args.include),
|
||||
infile
|
||||
]).check_returncode()
|
||||
infile,
|
||||
]
|
||||
).check_returncode()
|
||||
|
||||
@@ -1,60 +1,72 @@
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import frontmatter
|
||||
import pathlib
|
||||
from collections import defaultdict
|
||||
|
||||
def cxx_escape_character(c):
|
||||
if ord(c) >= 0x20 and ord(c) < 0x7f and c != '"' and c != '?' and c != '\\':
|
||||
|
||||
def cxx_escape_character(c: str) -> str:
|
||||
if 0x20 <= ord(c) < 0x7F and c != '"' and c != "?" and c != "\\":
|
||||
return c
|
||||
elif c == '\t':
|
||||
return r'\t'
|
||||
elif c == '\n':
|
||||
return r'\n'
|
||||
elif c == '\r':
|
||||
return r'\r'
|
||||
elif c == '"':
|
||||
return r'\"'
|
||||
elif c == '?':
|
||||
return r'\?'
|
||||
elif c == '\\':
|
||||
return r'\\'
|
||||
elif ord(c) <= 0xffff:
|
||||
return str.format(r'\u{:04x}', ord(c))
|
||||
else:
|
||||
return str.format(r'\U{:08x}', ord(c))
|
||||
if c == "\t":
|
||||
return r"\t"
|
||||
if c == "\n":
|
||||
return r"\n"
|
||||
if c == "\r":
|
||||
return r"\r"
|
||||
if c == '"':
|
||||
return r"\""
|
||||
if c == "?":
|
||||
return r"\?"
|
||||
if c == "\\":
|
||||
return r"\\"
|
||||
if ord(c) <= 0xFFFF:
|
||||
return str.format(r"\u{:04x}", ord(c))
|
||||
return str.format(r"\U{:08x}", ord(c))
|
||||
|
||||
def cxx_literal(v):
|
||||
|
||||
def cxx_literal(v: Any) -> str:
|
||||
if v is None:
|
||||
return 'std::nullopt'
|
||||
elif isinstance(v, bool) and v == False: # 0 == False
|
||||
return 'false'
|
||||
elif isinstance(v, bool) and v == True: # 1 == True
|
||||
return 'true'
|
||||
elif isinstance(v, int):
|
||||
return "std::nullopt"
|
||||
if v is False:
|
||||
return "false"
|
||||
if v is True:
|
||||
return "true"
|
||||
if isinstance(v, int):
|
||||
return str(v)
|
||||
elif isinstance(v, str):
|
||||
return ''.join(['"', *(cxx_escape_character(c) for c in v), '"'])
|
||||
elif isinstance(v, list):
|
||||
return f'{{{", ".join([cxx_literal(item) for item in v])}}}'
|
||||
else:
|
||||
raise NotImplementedError(f'cannot represent {repr(v)} in C++')
|
||||
if isinstance(v, str):
|
||||
return "".join(['"', *(cxx_escape_character(c) for c in v), '"'])
|
||||
if isinstance(v, list):
|
||||
return f"{{{', '.join([cxx_literal(item) for item in v])}}}"
|
||||
msg = f"cannot represent {v!r} in C++"
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
def load_data(defs, parse_function):
|
||||
|
||||
def load_data[T](defs: list[str], parse_function: Callable[[frontmatter.Post], T]) -> list[T]:
|
||||
data = []
|
||||
for path in defs:
|
||||
try:
|
||||
datum = frontmatter.load(path)
|
||||
data.append((path, parse_function(datum)))
|
||||
except Exception as e:
|
||||
e.add_note(f'in {path}')
|
||||
e.add_note(f"in {path}")
|
||||
raise
|
||||
return data
|
||||
|
||||
def generate_file(path, data, sort_key_function, generate_function):
|
||||
|
||||
def generate_file(
|
||||
path: str | None,
|
||||
data: list[Any],
|
||||
sort_key_function: Callable[[Any], str],
|
||||
generate_function: Callable[[Any], str],
|
||||
):
|
||||
if path is not None:
|
||||
with open(path, 'w') as out:
|
||||
for path, datum in sorted(data, key=lambda pathAndDatum: sort_key_function(pathAndDatum[1])):
|
||||
with Path(path).open("w") as out:
|
||||
for path, datum in sorted(
|
||||
data, key=lambda path_and_datum: sort_key_function(path_and_datum[1])
|
||||
):
|
||||
try:
|
||||
out.write(generate_function(datum))
|
||||
except Exception as e:
|
||||
e.add_note(f'in {path}')
|
||||
e.add_note(f"in {path}")
|
||||
raise
|
||||
|
||||
+1
-1
@@ -12,5 +12,5 @@ priority = 0
|
||||
[formatter.ruff]
|
||||
command = "ruff"
|
||||
options = ["check"]
|
||||
includes = ["tests/functional2/**/*.py", "meson/clang-tidy/*.py", "maintainers/*.py"]
|
||||
includes = ["tests/functional2/**/*.py", "meson/clang-tidy/*.py", "maintainers/*.py", "lix/code-generation/*.py"]
|
||||
priority = 1
|
||||
|
||||
Reference in New Issue
Block a user