diff --git a/cranelift/isle/src/codegen.rs b/cranelift/isle/src/codegen.rs index e080f30a25..4a12c5d7c9 100644 --- a/cranelift/isle/src/codegen.rs +++ b/cranelift/isle/src/codegen.rs @@ -2,8 +2,9 @@ use crate::error::Error; use crate::ir::{lower_rule, ExprSequence, PatternInst, PatternSequence}; -use crate::sema::{RuleId, TermEnv, TermId, TypeEnv}; +use crate::sema::{RuleId, TermEnv, TermId, Type, TypeEnv}; use std::collections::HashMap; +use std::fmt::Write; /// One "input symbol" for the decision tree that handles matching on /// a term. Each symbol represents one step: we either run a match op, @@ -509,9 +510,49 @@ impl<'a> Codegen<'a> { } pub fn generate_rust(&self) -> Result { - use std::fmt::Write; let mut code = String::new(); writeln!(&mut code, "// GENERATED BY ISLE. DO NOT EDIT!")?; + writeln!( + &mut code, + "use super::*; // Pulls in all external types and ctors/etors" + )?; + self.generate_internal_types(&mut code)?; Ok(code) } + + fn generate_internal_types(&self, code: &mut dyn Write) -> Result<(), Error> { + for ty in &self.typeenv.types { + match ty { + &Type::Enum { + name, + is_extern, + ref variants, + pos, + .. + } if !is_extern => { + let name = &self.typeenv.syms[name.index()]; + writeln!( + code, + "\n// Internal type {}: defined at {}.", + name, + pos.pretty_print_line(&self.typeenv.filename) + )?; + writeln!(code, "enum {} {{", name)?; + for variant in variants { + let name = &self.typeenv.syms[variant.name.index()]; + writeln!(code, " {} {{", name)?; + for field in &variant.fields { + let name = &self.typeenv.syms[field.name.index()]; + let ty_name = self.typeenv.types[field.ty.index()].name(&self.typeenv); + writeln!(code, " {}: {},", name, ty_name)?; + } + writeln!(code, " }}")?; + } + writeln!(code, "}}")?; + } + _ => {} + } + } + Ok(()) + } } diff --git a/cranelift/isle/src/lexer.rs b/cranelift/isle/src/lexer.rs index eafb72a462..f9672db298 100644 --- a/cranelift/isle/src/lexer.rs +++ b/cranelift/isle/src/lexer.rs @@ -14,6 +14,15 @@ pub struct Pos { pub col: usize, } +impl Pos { + pub fn pretty_print(&self, filename: &str) -> String { + format!("{}:{}:{}", filename, self.line, self.col) + } + pub fn pretty_print_line(&self, filename: &str) -> String { + format!("{} line {}", filename, self.line) + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Token<'a> { LParen, diff --git a/cranelift/isle/src/sema.rs b/cranelift/isle/src/sema.rs index 9e2bab9fe0..ff6a2d219e 100644 --- a/cranelift/isle/src/sema.rs +++ b/cranelift/isle/src/sema.rs @@ -50,7 +50,7 @@ pub enum Type { } impl Type { - fn name<'a>(&self, tyenv: &'a TypeEnv) -> &'a str { + pub fn name<'a>(&self, tyenv: &'a TypeEnv) -> &'a str { match self { Self::Primitive(_, name) | Self::Enum { name, .. } => &tyenv.syms[name.index()], } @@ -60,6 +60,7 @@ impl Type { #[derive(Clone, Debug, PartialEq, Eq)] pub struct Variant { pub name: Sym, + pub fullname: Sym, pub id: VariantId, pub fields: Vec, } @@ -209,9 +210,10 @@ impl TypeEnv { let mut variants = vec![]; for variant in ty_variants { let combined_ident = ast::Ident(format!("{}.{}", ty.name.0, variant.name.0)); - let var_name = self.intern_mut(&combined_ident); + let fullname = self.intern_mut(&combined_ident); + let name = self.intern_mut(&variant.name); let id = VariantId(variants.len()); - if variants.iter().any(|v: &Variant| v.name == var_name) { + if variants.iter().any(|v: &Variant| v.name == name) { return Err(self.error( ty.pos, format!("Duplicate variant name in type: '{}'", variant.name.0), @@ -249,7 +251,8 @@ impl TypeEnv { }); } variants.push(Variant { - name: var_name, + name, + fullname, id, fields, }); @@ -376,12 +379,12 @@ impl TermEnv { .. } => { for variant in variants { - if self.term_map.contains_key(&variant.name) { + if self.term_map.contains_key(&variant.fullname) { return Err(tyenv.error( pos, format!( "Duplicate enum variant constructor: '{}'", - tyenv.syms[variant.name.index()] + tyenv.syms[variant.fullname.index()] ), )); } @@ -390,14 +393,14 @@ impl TermEnv { let ret_ty = id; self.terms.push(Term { id: tid, - name: variant.name, + name: variant.fullname, arg_tys, ret_ty, kind: TermKind::EnumVariant { variant: variant.id, }, }); - self.term_map.insert(variant.name, tid); + self.term_map.insert(variant.fullname, tid); } } _ => {}