diff --git a/amaranth/build/plat.py b/amaranth/build/plat.py index 6fc6ad0..4b922a9 100644 --- a/amaranth/build/plat.py +++ b/amaranth/build/plat.py @@ -315,6 +315,50 @@ class TemplatedPlatform(Platform): rtlil_text, self._name_map = rtlil.convert_fragment(fragment, name=name) + # Retrieve an override specified in either the environment or as a kwarg. + # expected_type parameter is used to assert the type of kwargs, passing `None` will disable + # type checking. + def _extract_override(var, *, expected_type): + deprecated_var_env = "NMIGEN_{}".format(var) + var_env = "AMARANTH_{}".format(var) + if deprecated_var_env in os.environ or var_env in os.environ: + # On Windows, there is no way to define an "empty but set" variable; it is tempting + # to use a quoted empty string, but it doesn't do what one would expect. Recognize + # this as a useful pattern anyway, and treat `set VAR=""` on Windows the same way + # `export VAR=` is treated on Linux. + if var_env in os.environ: + var_env_value = os.environ[var_env] + elif deprecated_var_env in os.environ: + var_env_value = os.environ[deprecated_var_env] + return re.sub(r'^\"\"$', "", var_env_value) + elif var in kwargs: + if not isinstance(kwargs[var], expected_type) and not expected_type is None: + raise TypeError("Override '{}' must be a {}, not {!r}".format(var, expected_type.__name__, kwargs[var])) + else: + return kwargs[var] + else: + return jinja2.Undefined(name=var) + + def get_override(var): + value = _extract_override(var, expected_type=str) + return value + + def get_override_flag(var): + value = _extract_override(var, expected_type=bool) + if isinstance(value, str): + value = value.lower() + if value in ("0", "no", "n", "false", ""): + return False + if value in ("1", "yes", "y", "true"): + return True + else: + raise ValueError("Override '{}' must be one of " + "(\"0\", \"n\", \"no\", \"false\", \"\") " + "or " + "(\"1\", \"y\", \"yes\", \"true\"), not {!r}" + .format(var, value)) + return value + def emit_rtlil(): return rtlil_text @@ -354,27 +398,6 @@ class TemplatedPlatform(Platform): return "\n".join(commands) - def get_override(var): - deprecated_var_env = "NMIGEN_{}".format(var) - var_env = "AMARANTH_{}".format(var) - if deprecated_var_env in os.environ or var_env in os.environ: - # On Windows, there is no way to define an "empty but set" variable; it is tempting - # to use a quoted empty string, but it doesn't do what one would expect. Recognize - # this as a useful pattern anyway, and treat `set VAR=""` on Windows the same way - # `export VAR=` is treated on Linux. - if var_env in os.environ: - var_env_value = os.environ[var_env] - elif deprecated_var_env in os.environ: - var_env_value = os.environ[deprecated_var_env] - return re.sub(r'^\"\"$', "", var_env_value) - elif var in kwargs: - if isinstance(kwargs[var], str): - return textwrap.dedent(kwargs[var]).strip() - else: - return kwargs[var] - else: - return jinja2.Undefined(name=var) - @jinja2.pass_context def invoke_tool(context, name): env_var = tool_env_var(name) @@ -409,13 +432,13 @@ class TemplatedPlatform(Platform): return '"' + re.sub(r"([$[\\])", r"\\\1", string) + '"' def verbose(arg): - if get_override("verbose"): + if get_override_flag("verbose"): return arg else: return jinja2.Undefined(name="quiet") def quiet(arg): - if get_override("verbose"): + if get_override_flag("verbose"): return jinja2.Undefined(name="quiet") else: return arg @@ -443,6 +466,7 @@ class TemplatedPlatform(Platform): "syntax": syntax, "invoke_tool": invoke_tool, "get_override": get_override, + "get_override_flag": get_override_flag, "verbose": verbose, "quiet": quiet, "autogenerated": autogenerated,