#!/usr/bin/env python3 """Generates libs/relax/front/src/feature_tables.rs from rustc 1.97.1's rustc_feature crate. python3 feature_tables.py /compiler/rustc_feature/src > ../src/feature_tables.rs Sources: unstable.rs (ACTIVE lang features), accepted.rs, removed.rs, builtin_attrs.rs (BUILTIN_ATTRIBUTES: the gated entries and GATED_CFGS). """ import re, sys src = sys.argv[1] def read(n): return open(src + "/" + n).read() def feats(text, kind): out = [] for m in re.finditer(r"^\s*\(%s,\s*(\w+),\s*\"([^\"]*)\"" % kind, text, re.M): out.append((m.group(1), m.group(2))) return out def rs(s): return '"' + s.replace("\\", "\\\\").replace('"', '\\"') + '"' def args_of(text, start): """The top-level comma separated arguments of the macro call whose '(' is at text[start].""" depth, i, cur, out, instr = 0, start, [], [], False while i < len(text): c = text[i] if instr: cur.append(c) if c == "\\": cur.append(text[i + 1]); i += 1 elif c == '"': instr = False elif c == '"': instr = True; cur.append(c) elif c in "([": depth += 1 if depth > 1: cur.append(c) elif c in ")]": depth -= 1 if depth == 0: out.append("".join(cur).strip()); return out, i cur.append(c) elif c == "," and depth == 1: out.append("".join(cur).strip()); cur = [] else: cur.append(c) i += 1 raise SystemExit("unbalanced") def lit(s): """Value of a Rust string literal / experimental!(x) / concat!(..) argument.""" s = s.strip() m = re.fullmatch(r"experimental!\((\w+)\)", s) if m: return "the `#[%s]` attribute is an experimental feature" % m.group(1) if s.startswith("concat!"): return None assert s.startswith('"') and s.endswith('"'), s body = s[1:-1] body = re.sub(r"\\\n\s*", "", body) return body.replace('\\"', '"').replace("\\\\", "\\") unstable = feats(read("unstable.rs"), "unstable") + feats(read("unstable.rs"), "incomplete") + feats(read("unstable.rs"), "internal") accepted = feats(read("accepted.rs"), "accepted") removed = feats(read("removed.rs"), "removed") battr = read("builtin_attrs.rs") body = battr[battr.index("pub static BUILTIN_ATTRIBUTES"):] body = re.sub(r"(?m)^\s*//.*$", "", body) body = re.sub(r"(?m)\s//[^\"\n]*$", "", body) gated = [] # (attr, feature, message) for m in re.finditer(r"^\s*(gated|rustc_attr)!\(", body, re.M): kind = m.group(1) args, _ = args_of(body, m.end() - 1) if kind == "gated": name = args[0] if len(args) >= 3 and re.fullmatch(r"\w+", args[1]): feat, msg = args[1], lit(args[2]) else: feat, msg = name, lit(args[1]) else: if args[0] == "TEST": name = args[1] else: name = args[0] feat, msg = "rustc_attrs", "use of an internal attribute" gated.append((name, feat, msg)) gated.append(("rustc_diagnostic_item", "rustc_attrs", "use of an internal attribute")) gated.sort() gcfg = [] g = battr[battr.index("const GATED_CFGS"):battr.index("/// Find a gated cfg")] for m in re.finditer(r"\(\s*sym::(\w+),\s*sym::(\w+),", g): gcfg.append((m.group(1), m.group(2))) o = [] o.append("// @generated by libs/relax/front/gen/feature_tables.py from rustc 1.97.1 rustc_feature; do not edit.") o.append("") o.append("/// ACTIVE lang features (unstable.rs), by name.") o.append("pub static UNSTABLE: &[&str] = &[") for n, _ in unstable: o.append(" %s," % rs(n)) o.append("];\n") o.append("/// ACCEPTED lang features (accepted.rs): name, stable since.") o.append("pub static ACCEPTED: &[(&str, &str)] = &[") for n, v in accepted: o.append(" (%s, %s)," % (rs(n), rs(v))) o.append("];\n") o.append("/// REMOVED lang features (removed.rs): name.") o.append("pub static REMOVED: &[&str] = &[") for n, _ in removed: o.append(" %s," % rs(n)) o.append("];\n") o.append("/// The gated entries of BUILTIN_ATTRIBUTES: attribute, feature, message.") o.append("pub static GATED_ATTRS: &[(&str, &str, &str)] = &[") for n, f, m in gated: o.append(" (%s, %s, %s)," % (rs(n), rs(f), rs(m))) o.append("];\n") o.append("/// GATED_CFGS: cfg name, feature.") o.append("pub static GATED_CFGS: &[(&str, &str)] = &[") for n, f in gcfg: o.append(" (%s, %s)," % (rs(n), rs(f))) o.append("];") print("\n".join(o))