ISLE: Add a nodebug type attribute to disable derive(Debug)

I need this to move the x64 `Inst` definition into ISLE without losing its
custom `Debug` implementation that prints the assembly for the `Inst`.
This commit is contained in:
Nick Fitzgerald
2022-01-25 14:38:23 -08:00
parent 605c79fd05
commit e1f4e29efe
5 changed files with 63 additions and 19 deletions

View File

@@ -32,6 +32,7 @@ pub struct Ident(pub String, pub Pos);
pub struct Type { pub struct Type {
pub name: Ident, pub name: Ident,
pub is_extern: bool, pub is_extern: bool,
pub is_nodebug: bool,
pub ty: TypeValue, pub ty: TypeValue,
pub pos: Pos, pub pos: Pos,
} }

View File

@@ -138,6 +138,7 @@ impl<'a> Codegen<'a> {
&Type::Enum { &Type::Enum {
name, name,
is_extern, is_extern,
is_nodebug,
ref variants, ref variants,
pos, pos,
.. ..
@@ -150,11 +151,20 @@ impl<'a> Codegen<'a> {
pos.pretty_print_line(&self.typeenv.filenames[..]) pos.pretty_print_line(&self.typeenv.filenames[..])
) )
.unwrap(); .unwrap();
// Generate the `derive`s.
let debug_derive = if is_nodebug { "" } else { ", Debug" };
if variants.iter().all(|v| v.fields.is_empty()) { if variants.iter().all(|v| v.fields.is_empty()) {
writeln!(code, "#[derive(Copy, Clone, Debug, PartialEq, Eq)]").unwrap(); writeln!(
code,
"#[derive(Copy, Clone, PartialEq, Eq{})]",
debug_derive
)
.unwrap();
} else { } else {
writeln!(code, "#[derive(Clone, Debug)]").unwrap(); writeln!(code, "#[derive(Clone{})]", debug_derive).unwrap();
} }
writeln!(code, "pub enum {} {{", name).unwrap(); writeln!(code, "pub enum {} {{", name).unwrap();
for variant in variants { for variant in variants {
let name = &self.typeenv.syms[variant.name.index()]; let name = &self.typeenv.syms[variant.name.index()];

View File

@@ -197,15 +197,29 @@ impl<'a> Parser<'a> {
fn parse_type(&mut self) -> Result<Type> { fn parse_type(&mut self) -> Result<Type> {
let pos = self.pos(); let pos = self.pos();
let name = self.parse_ident()?; let name = self.parse_ident()?;
let mut is_extern = false; let mut is_extern = false;
if self.is_sym_str("extern") { let mut is_nodebug = false;
self.symbol()?;
is_extern = true; while self.lexer.peek().map_or(false, |(_pos, tok)| tok.is_sym()) {
let sym = self.symbol()?;
if sym == "extern" {
is_extern = true;
} else if sym == "nodebug" {
is_nodebug = true;
} else {
return Err(self.error(
self.pos(),
format!("unknown type declaration modifier: {}", sym),
));
}
} }
let ty = self.parse_typevalue()?; let ty = self.parse_typevalue()?;
Ok(Type { Ok(Type {
name, name,
is_extern, is_extern,
is_nodebug,
ty, ty,
pos, pos,
}) })

View File

@@ -109,6 +109,10 @@ pub enum Type {
/// If so, ISLE will not emit a definition for it. If not, then it will /// If so, ISLE will not emit a definition for it. If not, then it will
/// emit a Rust definition for it. /// emit a Rust definition for it.
is_extern: bool, is_extern: bool,
/// Whether this type should *not* derive `Debug`.
///
/// Incompatible with `is_extern`.
is_nodebug: bool,
/// The different variants for this enum. /// The different variants for this enum.
variants: Vec<Variant>, variants: Vec<Variant>,
/// The ISLE source position where this `enum` is defined. /// The ISLE source position where this `enum` is defined.
@@ -607,7 +611,7 @@ impl TypeEnv {
let ty = match tyenv.type_map.get(&ty) { let ty = match tyenv.type_map.get(&ty) {
Some(ty) => *ty, Some(ty) => *ty,
None => { None => {
tyenv.report_error(pos, "Unknown type for constant".into()); tyenv.report_error(pos, "Unknown type for constant");
continue; continue;
} }
}; };
@@ -635,9 +639,22 @@ impl TypeEnv {
let name = self.intern(&ty.name).unwrap(); let name = self.intern(&ty.name).unwrap();
match &ty.ty { match &ty.ty {
&ast::TypeValue::Primitive(ref id, ..) => { &ast::TypeValue::Primitive(ref id, ..) => {
if ty.is_nodebug {
self.report_error(ty.pos, "primitive types cannot be marked `nodebug`");
return None;
}
if ty.is_extern {
self.report_error(ty.pos, "primitive types cannot be marked `extern`");
return None;
}
Some(Type::Primitive(tid, self.intern_mut(id), ty.pos)) Some(Type::Primitive(tid, self.intern_mut(id), ty.pos))
} }
&ast::TypeValue::Enum(ref ty_variants, ..) => { &ast::TypeValue::Enum(ref ty_variants, ..) => {
if ty.is_extern && ty.is_nodebug {
self.report_error(ty.pos, "external types cannot be marked `nodebug`");
return None;
}
let mut variants = vec![]; let mut variants = vec![];
for variant in ty_variants { for variant in ty_variants {
let combined_ident = let combined_ident =
@@ -696,6 +713,7 @@ impl TypeEnv {
name, name,
id: tid, id: tid,
is_extern: ty.is_extern, is_extern: ty.is_extern,
is_nodebug: ty.is_nodebug,
variants, variants,
pos: ty.pos, pos: ty.pos,
}) })
@@ -703,9 +721,9 @@ impl TypeEnv {
} }
} }
fn error(&self, pos: Pos, msg: String) -> Error { fn error(&self, pos: Pos, msg: impl Into<String>) -> Error {
let e = Error::TypeError { let e = Error::TypeError {
msg, msg: msg.into(),
src: Source::new( src: Source::new(
self.filenames[pos.file].clone(), self.filenames[pos.file].clone(),
self.file_texts[pos.file].clone(), self.file_texts[pos.file].clone(),
@@ -716,7 +734,7 @@ impl TypeEnv {
e e
} }
fn report_error(&mut self, pos: Pos, msg: String) { fn report_error(&mut self, pos: Pos, msg: impl Into<String>) {
let err = self.error(pos, msg); let err = self.error(pos, msg);
self.errors.push(err); self.errors.push(err);
} }
@@ -987,8 +1005,7 @@ impl TermEnv {
tyenv.report_error( tyenv.report_error(
ext.pos, ext.pos,
"Extractor macro body defined on term of incorrect kind; cannot be an \ "Extractor macro body defined on term of incorrect kind; cannot be an \
enum variant" enum variant",
.into(),
); );
continue; continue;
} }
@@ -1329,10 +1346,7 @@ impl TermEnv {
let ty = match expected_ty { let ty = match expected_ty {
Some(t) => t, Some(t) => t,
None => { None => {
tyenv.report_error( tyenv.report_error(pos, "Need an implied type for an integer constant");
pos,
"Need an implied type for an integer constant".into(),
);
return None; return None;
} }
}; };
@@ -1353,12 +1367,12 @@ impl TermEnv {
let const_ty = match tyenv.const_types.get(&val) { let const_ty = match tyenv.const_types.get(&val) {
Some(ty) => *ty, Some(ty) => *ty,
None => { None => {
tyenv.report_error(pos, "Unknown constant".into()); tyenv.report_error(pos, "Unknown constant");
return None; return None;
} }
}; };
if expected_ty.is_some() && expected_ty != Some(const_ty) { if expected_ty.is_some() && expected_ty != Some(const_ty) {
tyenv.report_error(pos, "Type mismatch for constant".into()); tyenv.report_error(pos, "Type mismatch for constant");
} }
Some((Pattern::ConstPrim(const_ty, val), const_ty)) Some((Pattern::ConstPrim(const_ty, val), const_ty))
} }
@@ -1366,7 +1380,7 @@ impl TermEnv {
let ty = match expected_ty { let ty = match expected_ty {
Some(t) => t, Some(t) => t,
None => { None => {
tyenv.report_error(pos, "Need an implied type for a wildcard".into()); tyenv.report_error(pos, "Need an implied type for a wildcard");
return None; return None;
} }
}; };
@@ -1775,7 +1789,7 @@ impl TermEnv {
let const_ty = match tyenv.const_types.get(&val) { let const_ty = match tyenv.const_types.get(&val) {
Some(ty) => *ty, Some(ty) => *ty,
None => { None => {
tyenv.report_error(pos, "Unknown constant".into()); tyenv.report_error(pos, "Unknown constant");
return None; return None;
} }
}; };
@@ -1920,6 +1934,7 @@ mod test {
name: sym_a, name: sym_a,
id: TypeId(1), id: TypeId(1),
is_extern: true, is_extern: true,
is_nodebug: false,
variants: vec![ variants: vec![
Variant { Variant {
name: sym_b, name: sym_b,

View File

@@ -0,0 +1,4 @@
(type DoesNotDeriveDebug nodebug
(enum A
B
C))