From dee62ee036c2ff13e921186e5ab5e6556c049403 Mon Sep 17 00:00:00 2001
From: Vincent Lafeychine <vincent.lafeychine@proton.me>
Date: Mon, 17 Jun 2024 10:25:50 +0200
Subject: [PATCH] chore(radium): Split coq crate (command, term)

---
 rr_frontend/radium/src/code.rs                |  38 +-
 rr_frontend/radium/src/coq/command.rs         | 277 ++++++++
 rr_frontend/radium/src/coq/mod.rs             | 646 +-----------------
 rr_frontend/radium/src/coq/module.rs          |   2 +-
 rr_frontend/radium/src/coq/term.rs            | 414 +++++++++++
 rr_frontend/radium/src/specs.rs               | 482 +++++++------
 rr_frontend/translation/src/function_body.rs  |  28 +-
 rr_frontend/translation/src/lib.rs            |   2 +-
 .../src/spec_parsers/crate_attr_parser.rs     |  10 +-
 .../src/spec_parsers/enum_spec_parser.rs      |   4 +-
 .../src/spec_parsers/module_attr_parser.rs    |  10 +-
 .../src/spec_parsers/parse_utils.rs           |  14 +-
 .../src/spec_parsers/struct_spec_parser.rs    |  20 +-
 .../src/spec_parsers/trait_attr_parser.rs     |   9 +-
 .../spec_parsers/trait_impl_attr_parser.rs    |   2 +-
 .../verbose_function_spec_parser.rs           |  22 +-
 rr_frontend/translation/src/trait_registry.rs |   5 +-
 .../translation/src/type_translator.rs        |  21 +-
 18 files changed, 1052 insertions(+), 954 deletions(-)
 create mode 100644 rr_frontend/radium/src/coq/command.rs
 create mode 100644 rr_frontend/radium/src/coq/term.rs

diff --git a/rr_frontend/radium/src/code.rs b/rr_frontend/radium/src/code.rs
index ff115ea..1ab1b7f 100644
--- a/rr_frontend/radium/src/code.rs
+++ b/rr_frontend/radium/src/code.rs
@@ -277,13 +277,13 @@ pub enum Expr {
 
     #[display("StructInit {} [{}]", sls, display_list!(components, "; ", |(name, e)| format!("(\"{name}\", {e} : expr)")))]
     StructInitE {
-        sls: coq::AppTerm<String, String>,
+        sls: coq::term::App<String, String>,
         components: Vec<(String, Expr)>,
     },
 
     #[display("EnumInit {} \"{}\" ({}) ({})", els, variant, ty, &initializer)]
     EnumInitE {
-        els: coq::AppTerm<String, String>,
+        els: coq::term::App<String, String>,
         variant: String,
         ty: RustType,
         initializer: Box<Expr>,
@@ -651,7 +651,7 @@ pub struct FunctionCode {
     basic_blocks: BTreeMap<usize, Stmt>,
 
     /// Coq parameters that the function is parameterized over
-    required_parameters: Vec<(coq::Name, coq::Type)>,
+    required_parameters: Vec<(coq::term::Name, coq::term::Type)>,
 }
 
 fn make_map_string(sep0: &str, sep: &str, els: &Vec<(String, String)>) -> String {
@@ -677,7 +677,7 @@ fn make_lft_map_string(els: &Vec<(String, String)>) -> String {
 
 impl Display for FunctionCode {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fn fmt_params((name, ty): &(coq::Name, coq::Type)) -> String {
+        fn fmt_params((name, ty): &(coq::term::Name, coq::term::Type)) -> String {
             format!("({} : {})", name, ty)
         }
 
@@ -1294,12 +1294,12 @@ impl<'def> FunctionBuilder<'def> {
     }
 
     /// Add a Coq-level param that comes before the type parameters.
-    pub fn add_early_coq_param(&mut self, param: coq::Param) {
+    pub fn add_early_coq_param(&mut self, param: coq::term::Param) {
         self.spec.early_coq_params.0.push(param);
     }
 
     /// Add a Coq-level param that comes after the type parameters.
-    pub fn add_late_coq_param(&mut self, param: coq::Param) {
+    pub fn add_late_coq_param(&mut self, param: coq::term::Param) {
         self.spec.late_coq_params.0.push(param);
     }
 
@@ -1333,9 +1333,9 @@ impl<'def> FunctionBuilder<'def> {
             let spec_type = format!("{} {spec_params_param_name}", trait_use.trait_ref.spec_record);
 
             // add the spec params
-            self.spec.late_coq_params.0.push(coq::Param::new(
-                coq::Name::Named(spec_params_param_name),
-                coq::Type::Literal(spec_params_type_name),
+            self.spec.late_coq_params.0.push(coq::term::Param::new(
+                coq::term::Name::Named(spec_params_param_name),
+                coq::term::Type::Literal(spec_params_type_name),
                 true,
             ));
 
@@ -1348,16 +1348,16 @@ impl<'def> FunctionBuilder<'def> {
                 .collect();
             let mut attr_param = format!("{} ", trait_use.trait_ref.spec_attrs_record);
             push_str_list!(attr_param, &all_args, " ");
-            self.spec.late_coq_params.0.push(coq::Param::new(
-                coq::Name::Named(spec_attrs_param_name),
-                coq::Type::Literal(attr_param),
+            self.spec.late_coq_params.0.push(coq::term::Param::new(
+                coq::term::Name::Named(spec_attrs_param_name),
+                coq::term::Type::Literal(attr_param),
                 false,
             ));
 
             // add the spec itself
-            self.spec.late_coq_params.0.push(coq::Param::new(
-                coq::Name::Named(spec_param_name),
-                coq::Type::Literal(spec_type),
+            self.spec.late_coq_params.0.push(coq::term::Param::new(
+                coq::term::Name::Named(spec_param_name),
+                coq::term::Type::Literal(spec_type),
                 false,
             ));
 
@@ -1383,17 +1383,17 @@ impl<'def> FunctionBuilder<'def> {
 
         // generate location parameters for other functions used by this one, as well as syntypes
         // These are parameters that the code gets
-        let mut parameters: Vec<(coq::Name, coq::Type)> = self
+        let mut parameters: Vec<(coq::term::Name, coq::term::Type)> = self
             .other_functions
             .iter()
-            .map(|f_inst| (coq::Name::Named(f_inst.loc_name.clone()), coq::Type::Loc))
+            .map(|f_inst| (coq::term::Name::Named(f_inst.loc_name.clone()), coq::term::Type::Loc))
             .collect();
 
         // generate location parameters for statics used by this function
         let mut statics_parameters = self
             .used_statics
             .iter()
-            .map(|s| (coq::Name::Named(s.loc_name.clone()), coq::Type::Loc))
+            .map(|s| (coq::term::Name::Named(s.loc_name.clone()), coq::term::Type::Loc))
             .collect();
         parameters.append(&mut statics_parameters);
 
@@ -1403,7 +1403,7 @@ impl<'def> FunctionBuilder<'def> {
             .generics
             .get_ty_params()
             .iter()
-            .map(|names| (coq::Name::Named(names.syn_type.clone()), coq::Type::SynType))
+            .map(|names| (coq::term::Name::Named(names.syn_type.clone()), coq::term::Type::SynType))
             .collect();
         parameters.append(&mut gen_st_parameters);
 
diff --git a/rr_frontend/radium/src/coq/command.rs b/rr_frontend/radium/src/coq/command.rs
new file mode 100644
index 0000000..7e159ea
--- /dev/null
+++ b/rr_frontend/radium/src/coq/command.rs
@@ -0,0 +1,277 @@
+// © 2023, The RefinedRust Developers and Contributors
+//
+// This Source Code Form is subject to the terms of the BSD-3-clause License.
+// If a copy of the BSD-3-clause license was not distributed with this
+// file, You can obtain one at https://opensource.org/license/bsd-3-clause/.
+
+/// Rocq commands.
+use std::fmt;
+use std::fmt::Write as fmtWrite;
+
+use derive_more::Display;
+use indent_write::fmt::IndentWriter;
+
+use crate::coq::term;
+use crate::{display_list, BASE_INDENT};
+
+/// A single tactic call.
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+pub enum ProofItem {
+    #[display("{}.", _0)]
+    Literal(String),
+}
+
+/// A Coq proof script.
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+#[display("{}\n", display_list!(_0, "\n"))]
+pub struct ProofScript(pub Vec<ProofItem>);
+
+/// A terminator for a proof script
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+pub enum ProofScriptTerminator {
+    #[display("Qed")]
+    Qed,
+
+    #[display("Defined")]
+    Defined,
+
+    #[display("Admitted")]
+    Admitted,
+}
+
+/// A body of a Coq definition
+#[derive(Clone, Eq, PartialEq, Debug)]
+pub enum DefBody {
+    /// a proof script invoking Ltac tactics
+    Script(ProofScript, ProofScriptTerminator),
+
+    /// a proof term
+    Term(term::Gallina),
+}
+
+impl Display for DefBody {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Script(script, terminator) => {
+                write!(f, ".\n")?;
+                write!(f, "Proof.\n")?;
+                let mut f2 = IndentWriter::new(BASE_INDENT, &mut *f);
+                write!(f2, "{}", script)?;
+                write!(f, "{}.", terminator)?;
+            },
+            Self::Term(term) => {
+                write!(f, " := {}.", term)?;
+            },
+        }
+        Ok(())
+    }
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+pub enum Attribute {
+    #[display("global")]
+    Global,
+
+    #[display("local")]
+    Local,
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+#[display("{}",
+    if attrs.is_empty() { String::new() } else {
+        format!("#[ {} ]", display_list!(attrs, ", "))
+    }
+)]
+pub struct Attributes {
+    attrs: Vec<Attribute>,
+}
+
+impl Attributes {
+    #[must_use]
+    pub const fn empty() -> Self {
+        Self { attrs: vec![] }
+    }
+
+    #[must_use]
+    pub fn new(attrs: Vec<Attribute>) -> Self {
+        Self { attrs }
+    }
+
+    #[must_use]
+    pub fn singleton(attr: Attribute) -> Self {
+        Self { attrs: vec![attr] }
+    }
+}
+
+/// A Coq typeclass instance declaration
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+#[display("#[global] Instance : {}{}", ty, body)]
+pub struct InstanceDecl {
+    ty: term::Type,
+    body: DefBody,
+}
+
+impl InstanceDecl {
+    #[must_use]
+    pub const fn new(ty: term::Type, body: DefBody) -> Self {
+        Self { ty, body }
+    }
+}
+
+#[derive(Clone, Debug, Display, Eq, PartialEq)]
+#[display("{} {} : {}", name, params, ty)]
+pub struct RecordDeclItem {
+    pub name: String,
+    pub params: term::ParamList,
+    pub ty: term::Type,
+}
+
+/// A record declaration.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Record {
+    pub name: String,
+    pub params: term::ParamList,
+    pub ty: term::Type,
+    pub constructor: Option<String>,
+    pub body: Vec<RecordDeclItem>,
+}
+
+impl Display for Record {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let constructor = self.constructor.clone().unwrap_or_default();
+        write!(f, "Record {} {} : {} := {constructor} {{\n", self.name, self.params, self.ty)?;
+        let mut f2 = IndentWriter::new(BASE_INDENT, &mut *f);
+        for it in &self.body {
+            write!(f2, "{it};\n")?;
+        }
+        write!(f, "}}.")
+    }
+}
+
+/// A Context declaration.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct ContextDecl {
+    pub items: term::ParamList,
+}
+
+impl ContextDecl {
+    #[must_use]
+    pub const fn new(items: term::ParamList) -> Self {
+        Self { items }
+    }
+
+    #[must_use]
+    pub fn refinedrust() -> Self {
+        Self {
+            items: term::ParamList::new(vec![term::Param::new(
+                term::Name::Named("RRGS".to_owned()),
+                term::Type::Literal("refinedrustGS Σ".to_owned()),
+                true,
+            )]),
+        }
+    }
+}
+
+impl Display for ContextDecl {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.items.0.is_empty() { Ok(()) } else { write!(f, "Context {}.", self.items) }
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq, Display)]
+pub enum DefinitionKind {
+    #[display("Definition")]
+    Definition,
+    #[display("Lemma")]
+    Lemma,
+}
+
+/// A Coq definition
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Definition {
+    pub name: String,
+    pub params: term::ParamList,
+    pub ty: Option<term::Type>,
+    pub body: DefBody,
+    pub kind: DefinitionKind,
+}
+
+impl Display for Definition {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if let Some(ty) = &self.ty {
+            write!(f, "{} {} {} : {ty}{}", self.kind, self.name, self.params, self.body)
+        } else {
+            write!(f, "{} {} {}{}", self.kind, self.name, self.params, self.body)
+        }
+    }
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+pub enum TopLevelAssertion<'a> {
+    /// A declaration of a Coq Inductive
+    #[display("{}", _0)]
+    InductiveDecl(&'a term::Inductive),
+
+    /// A declaration of a Coq instance
+    #[display("{}", _0)]
+    InstanceDecl(&'a InstanceDecl),
+
+    /// A declaration of a Coq record
+    #[display("{}", _0)]
+    RecordDecl(Record),
+
+    /// A declaration of Coq context items
+    #[display("{}", _0)]
+    ContextDecl(ContextDecl),
+
+    /// A Coq Definition
+    #[display("{}", _0)]
+    Definition(Definition),
+
+    /// A Coq comment
+    #[display("(* {} *)", _0)]
+    Comment(&'a str),
+
+    /// A Coq section
+    #[display("Section {}.\n{}End{}.", _0, Indented::new(_1), _0)]
+    Section(String, TopLevelAssertions<'a>),
+
+    /// A Coq section start
+    #[display("Section {}.", _0)]
+    SectionStart(String),
+
+    /// A Coq section end
+    #[display("End {}.", _0)]
+    SectionEnd(String),
+}
+
+/// Type for writing contents indented via Display.
+struct Indented<T> {
+    x: T,
+}
+impl<T> Indented<T> {
+    pub const fn new(x: T) -> Self {
+        Self { x }
+    }
+}
+impl<T: Display> Display for Indented<T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut indent_writer = IndentWriter::new(BASE_INDENT, f);
+        write!(indent_writer, "{}", self.x)
+    }
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+#[display("{}", display_list!(_0, "\n"))]
+pub struct TopLevelAssertions<'a>(pub Vec<TopLevelAssertion<'a>>);
+
+impl<'a> TopLevelAssertions<'a> {
+    #[must_use]
+    pub(crate) const fn empty() -> Self {
+        Self(vec![])
+    }
+
+    pub(crate) fn push(&mut self, a: TopLevelAssertion<'a>) {
+        self.0.push(a);
+    }
+}
diff --git a/rr_frontend/radium/src/coq/mod.rs b/rr_frontend/radium/src/coq/mod.rs
index 5f69817..f24104c 100644
--- a/rr_frontend/radium/src/coq/mod.rs
+++ b/rr_frontend/radium/src/coq/mod.rs
@@ -4,648 +4,10 @@
 // If a copy of the BSD-3-clause license was not distributed with this
 // file, You can obtain one at https://opensource.org/license/bsd-3-clause/.
 
-pub mod module;
-
 /// A collection of types to represent and generate Rocq code.
 ///
 /// These types are intended to be used for the purposes of this project.
-use std::fmt;
-use std::fmt::Write as fmtWrite;
-
-use derive_more::Display;
-use indent_write::fmt::IndentWriter;
-use indent_write::indentable::Indentable;
-use itertools::Itertools;
-
-use crate::{display_list, make_indent, write_list, BASE_INDENT};
-
-/// Represents an application of a term to an rhs.
-/// (commonly used for layouts and instantiating them with generics).
-#[derive(Clone, Eq, PartialEq, Hash, Debug)]
-pub struct AppTerm<T, U> {
-    pub(crate) lhs: T,
-    pub(crate) rhs: Vec<U>,
-}
-
-impl<T: Display, U: Display> Display for AppTerm<T, U> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if self.rhs.is_empty() {
-            return write!(f, "{}", self.lhs);
-        }
-
-        write_list!(f, &self.rhs, " ", "({})")
-    }
-}
-
-impl<T, U> AppTerm<T, U> {
-    pub fn new(lhs: T, rhs: Vec<U>) -> Self {
-        Self { lhs, rhs }
-    }
-
-    pub fn new_lhs(lhs: T) -> Self {
-        Self {
-            lhs,
-            rhs: Vec::new(),
-        }
-    }
-
-    pub(crate) const fn get_lhs(&self) -> &T {
-        &self.lhs
-    }
-}
-
-#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Display)]
-pub enum Name {
-    #[display("{}", _0)]
-    Named(String),
-
-    #[display("_")]
-    Unnamed,
-}
-
-/// A Coq pattern, e.g., "x" or "'(x, y)".
-pub type Pattern = String;
-
-fn fmt_prod(v: &Vec<Type>) -> String {
-    match v.as_slice() {
-        [] => "unit".to_owned(),
-        [t] => t.to_string(),
-        _ => format!("({})%type", display_list!(v, " * ")),
-    }
-}
-
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-pub enum Type {
-    /// literal types that are not contained in the grammar
-    #[display("{}", _0)]
-    Literal(String),
-
-    /// function types; the argument vector should be non-empty
-    #[display("{} → {}", display_list!(_0, " → ", "({})"), *_1)]
-    Function(Vec<Type>, Box<Type>),
-
-    /// Placeholder that should be inferred by Coq if possible
-    #[display("_")]
-    Infer,
-
-    /// Coq type `lft`
-    #[display("lft")]
-    Lft,
-
-    /// Coq type `loc`
-    #[display("loc")]
-    Loc,
-
-    /// Coq type `layout`
-    #[display("layout")]
-    Layout,
-
-    /// Coq type `syn_type`
-    #[display("syn_type")]
-    SynType,
-
-    /// Coq type `struct_layout`
-    #[display("struct_layout")]
-    StructLayout,
-
-    /// Coq type `Type`
-    #[display("Type")]
-    Type,
-
-    /// Coq type `type rt`
-    #[display("(type {})", &_0)]
-    Ttype(Box<Type>),
-
-    /// Coq type `rtype`
-    #[display("rtype")]
-    Rtype,
-
-    /// the unit type
-    #[display("unit")]
-    Unit,
-
-    /// the type of integers
-    #[display("Z")]
-    Z,
-
-    /// the type of booleans
-    #[display("bool")]
-    Bool,
-
-    /// product types
-    #[display("{}", fmt_prod(_0))]
-    Prod(Vec<Type>),
-
-    /// place_rfn
-    #[display("(place_rfn {})", &_0)]
-    PlaceRfn(Box<Type>),
-
-    /// gname
-    #[display("gname")]
-    Gname,
-
-    /// a plist with a given type constructor over a list of types
-    #[display("plist {} [{}]", _0, display_list!(_1, "; ", "{} : Type"))]
-    PList(String, Vec<Type>),
-
-    /// the semantic type of a function
-    #[display("function_ty")]
-    FunctionTy,
-
-    /// the Coq type Prop of propositions
-    #[display("Prop")]
-    Prop,
-}
-
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-#[display("{}", self.format(true))]
-pub struct Param {
-    /// the name
-    name: Name,
-
-    /// the type
-    ty: Type,
-
-    /// implicit or not?
-    implicit: bool,
-
-    /// does this depend on Σ?
-    depends_on_sigma: bool,
-}
-
-impl Param {
-    #[must_use]
-    pub fn new(name: Name, ty: Type, implicit: bool) -> Self {
-        let depends_on_sigma = if let Type::Literal(lit) = &ty { lit.contains('Σ') } else { false };
-
-        Self {
-            name,
-            ty,
-            implicit,
-            depends_on_sigma,
-        }
-    }
-
-    #[must_use]
-    pub fn with_name(&self, name: String) -> Self {
-        Self::new(Name::Named(name), self.ty.clone(), self.implicit)
-    }
-
-    #[must_use]
-    pub fn get_name_ref(&self) -> Option<&str> {
-        match &self.name {
-            Name::Named(s) => Some(s),
-            Name::Unnamed => None,
-        }
-    }
-
-    #[allow(clippy::collapsible_else_if)]
-    #[must_use]
-    fn format(&self, make_implicits: bool) -> String {
-        if !self.implicit {
-            return format!("({} : {})", self.name, self.ty);
-        }
-
-        if make_implicits {
-            if let Name::Named(name) = &self.name {
-                format!("`{{{} : !{}}}", name, self.ty)
-            } else {
-                format!("`{{!{}}}", self.ty)
-            }
-        } else {
-            if let Name::Named(name) = &self.name {
-                format!("`({} : !{})", name, self.ty)
-            } else {
-                format!("`(!{})", self.ty)
-            }
-        }
-    }
-
-    pub(crate) const fn get_name(&self) -> &Name {
-        &self.name
-    }
-
-    pub(crate) const fn is_implicit(&self) -> bool {
-        self.implicit
-    }
-
-    pub(crate) const fn is_dependent_on_sigma(&self) -> bool {
-        self.depends_on_sigma
-    }
-}
-
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-#[display("{}", display_list!(_0, " "))]
-pub struct ParamList(pub Vec<Param>);
-
-impl ParamList {
-    #[must_use]
-    pub const fn new(params: Vec<Param>) -> Self {
-        Self(params)
-    }
-
-    #[must_use]
-    pub const fn empty() -> Self {
-        Self(vec![])
-    }
-
-    pub fn append(&mut self, params: Vec<Param>) {
-        self.0.extend(params);
-    }
-
-    /// Make using terms for this list of binders
-    #[must_use]
-    pub fn make_using_terms(&self) -> Vec<GallinaTerm> {
-        self.0.iter().map(|x| GallinaTerm::Literal(format!("{}", x.name))).collect()
-    }
-}
-
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-#[display("{} {}", name, params)]
-pub struct Variant {
-    name: String,
-    params: ParamList,
-}
-
-impl Variant {
-    #[must_use]
-    pub fn new(name: &str, params: Vec<Param>) -> Self {
-        Self {
-            name: name.to_owned(),
-            params: ParamList::new(params),
-        }
-    }
-}
-
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-#[display("Inductive {} {} :=\n{}\n.", name, parameters,
-    display_list!(variants, "\n| ").indented(&make_indent(1))
-)]
-pub struct Inductive {
-    name: String,
-    parameters: ParamList,
-    variants: Vec<Variant>,
-}
-
-impl Inductive {
-    #[must_use]
-    pub fn new(name: &str, parameters: Vec<Param>, variants: Vec<Variant>) -> Self {
-        Self {
-            name: name.to_owned(),
-            parameters: ParamList::new(parameters),
-            variants,
-        }
-    }
-
-    pub(crate) const fn get_name(&self) -> &String {
-        &self.name
-    }
-}
-
-/// A single tactic call.
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-pub enum ProofItem {
-    #[display("{}.", _0)]
-    Literal(String),
-}
-
-/// A Coq proof script.
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-#[display("{}\n", display_list!(_0, "\n"))]
-pub struct ProofScript(pub Vec<ProofItem>);
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct RecordBodyItem {
-    pub name: String,
-    pub params: ParamList,
-    pub term: GallinaTerm,
-}
-
-impl Display for RecordBodyItem {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut writer = IndentWriter::new_skip_initial(BASE_INDENT, &mut *f);
-        write!(writer, "{} {} :=\n{};", self.name, self.params, self.term)
-    }
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct RecordBodyTerm {
-    pub items: Vec<RecordBodyItem>,
-}
-
-impl Display for RecordBodyTerm {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{{|\n")?;
-        let mut f2 = IndentWriter::new(BASE_INDENT, &mut *f);
-        for it in &self.items {
-            write!(f2, "{}\n", it)?;
-        }
-        write!(f, "|}}\n")
-    }
-}
-
-/// A Coq Gallina term.
-#[derive(Clone, Eq, PartialEq, Debug)]
-pub enum GallinaTerm {
-    /// a literal
-    Literal(String),
-    /// Application
-    App(Box<AppTerm<GallinaTerm, GallinaTerm>>),
-    /// a record body
-    RecordBody(RecordBodyTerm),
-    /// Projection a.(b) from a record
-    RecordProj(Box<GallinaTerm>, String),
-    /// Universal quantifiers
-    All(ParamList, Box<GallinaTerm>),
-    /// Existential quantifiers
-    Exists(ParamList, Box<GallinaTerm>),
-    /// Infix operators
-    Infix(String, Vec<GallinaTerm>),
-}
-
-impl Display for GallinaTerm {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Self::Literal(lit) => {
-                let mut f2 = IndentWriter::new_skip_initial(BASE_INDENT, &mut *f);
-                write!(f2, "{lit}")
-            },
-            Self::RecordBody(b) => {
-                write!(f, "{b}")
-            },
-            Self::RecordProj(rec, component) => {
-                write!(f, "{rec}.({component})")
-            },
-            Self::App(box a) => write!(f, "{a}"),
-            Self::All(binders, box body) => {
-                if !binders.0.is_empty() {
-                    write!(f, "∀ {binders}, ")?;
-                }
-                write!(f, "{body}")
-            },
-            Self::Exists(binders, box body) => {
-                if !binders.0.is_empty() {
-                    write!(f, "∃ {binders}, ")?;
-                }
-                write!(f, "{body}")
-            },
-            Self::Infix(op, terms) => {
-                if terms.is_empty() {
-                    write!(f, "True")
-                } else {
-                    write!(f, "{}", terms.iter().format(&format!(" {op} ")))
-                }
-            },
-        }
-    }
-}
-
-/// A terminator for a proof script
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-pub enum ProofScriptTerminator {
-    #[display("Qed")]
-    Qed,
-
-    #[display("Defined")]
-    Defined,
-
-    #[display("Admitted")]
-    Admitted,
-}
-
-/// A body of a Coq definition
-#[derive(Clone, Eq, PartialEq, Debug)]
-pub enum DefBody {
-    /// a proof script invoking Ltac tactics
-    Script(ProofScript, ProofScriptTerminator),
-
-    /// a proof term
-    Term(GallinaTerm),
-}
-
-impl Display for DefBody {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Self::Script(script, terminator) => {
-                write!(f, ".\n")?;
-                write!(f, "Proof.\n")?;
-                let mut f2 = IndentWriter::new(BASE_INDENT, &mut *f);
-                write!(f2, "{}", script)?;
-                write!(f, "{}.", terminator)?;
-            },
-            Self::Term(term) => {
-                write!(f, " := {}.", term)?;
-            },
-        }
-        Ok(())
-    }
-}
-
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-pub enum Attribute {
-    #[display("global")]
-    Global,
-
-    #[display("local")]
-    Local,
-}
-
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-#[display("{}",
-    if attrs.is_empty() { String::new() } else {
-        format!("#[ {} ]", display_list!(attrs, ", "))
-    }
-)]
-pub struct Attributes {
-    attrs: Vec<Attribute>,
-}
-
-impl Attributes {
-    #[must_use]
-    pub const fn empty() -> Self {
-        Self { attrs: vec![] }
-    }
-
-    #[must_use]
-    pub fn new(attrs: Vec<Attribute>) -> Self {
-        Self { attrs }
-    }
-
-    #[must_use]
-    pub fn singleton(attr: Attribute) -> Self {
-        Self { attrs: vec![attr] }
-    }
-}
-
-/// A Coq typeclass instance declaration
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-#[display("#[global] Instance : {}{}", ty, body)]
-pub struct InstanceDecl {
-    ty: Type,
-    body: DefBody,
-}
-
-impl InstanceDecl {
-    #[must_use]
-    pub const fn new(ty: Type, body: DefBody) -> Self {
-        Self { ty, body }
-    }
-}
-
-#[derive(Clone, Debug, Display, Eq, PartialEq)]
-#[display("{} {} : {}", name, params, ty)]
-pub struct RecordDeclItem {
-    pub name: String,
-    pub params: ParamList,
-    pub ty: Type,
-}
-
-/// A record declaration.
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct Record {
-    pub name: String,
-    pub params: ParamList,
-    pub ty: Type,
-    pub constructor: Option<String>,
-    pub body: Vec<RecordDeclItem>,
-}
-
-impl Display for Record {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let constructor = self.constructor.clone().unwrap_or_default();
-        write!(f, "Record {} {} : {} := {constructor} {{\n", self.name, self.params, self.ty)?;
-        let mut f2 = IndentWriter::new(BASE_INDENT, &mut *f);
-        for it in &self.body {
-            write!(f2, "{it};\n")?;
-        }
-        write!(f, "}}.")
-    }
-}
-
-/// A Context declaration.
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct ContextDecl {
-    pub items: ParamList,
-}
-
-impl ContextDecl {
-    #[must_use]
-    pub const fn new(items: ParamList) -> Self {
-        Self { items }
-    }
-
-    #[must_use]
-    pub fn refinedrust() -> Self {
-        Self {
-            items: ParamList::new(vec![Param::new(
-                Name::Named("RRGS".to_owned()),
-                Type::Literal("refinedrustGS Σ".to_owned()),
-                true,
-            )]),
-        }
-    }
-}
-
-impl Display for ContextDecl {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if self.items.0.is_empty() { Ok(()) } else { write!(f, "Context {}.", self.items) }
-    }
-}
-
-#[derive(Clone, Debug, Eq, PartialEq, Display)]
-pub enum DefinitionKind {
-    #[display("Definition")]
-    Definition,
-    #[display("Lemma")]
-    Lemma,
-}
-
-/// A Coq definition
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct Definition {
-    pub name: String,
-    pub params: ParamList,
-    pub ty: Option<Type>,
-    pub body: DefBody,
-    pub kind: DefinitionKind,
-}
-
-impl Display for Definition {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if let Some(ty) = &self.ty {
-            write!(f, "{} {} {} : {ty}{}", self.kind, self.name, self.params, self.body)
-        } else {
-            write!(f, "{} {} {}{}", self.kind, self.name, self.params, self.body)
-        }
-    }
-}
-
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-pub enum TopLevelAssertion<'a> {
-    /// A declaration of a Coq Inductive
-    #[display("{}", _0)]
-    InductiveDecl(&'a Inductive),
-
-    /// A declaration of a Coq instance
-    #[display("{}", _0)]
-    InstanceDecl(&'a InstanceDecl),
-
-    /// A declaration of a Coq record
-    #[display("{}", _0)]
-    RecordDecl(Record),
-
-    /// A declaration of Coq context items
-    #[display("{}", _0)]
-    ContextDecl(ContextDecl),
-
-    /// A Coq Definition
-    #[display("{}", _0)]
-    Definition(Definition),
-
-    /// A Coq comment
-    #[display("(* {} *)", _0)]
-    Comment(&'a str),
-
-    /// A Coq section
-    #[display("Section {}.\n{}End{}.", _0, Indented::new(_1), _0)]
-    Section(String, TopLevelAssertions<'a>),
-
-    /// A Coq section start
-    #[display("Section {}.", _0)]
-    SectionStart(String),
-
-    /// A Coq section end
-    #[display("End {}.", _0)]
-    SectionEnd(String),
-}
-
-/// Type for writing contents indented via Display.
-struct Indented<T> {
-    x: T,
-}
-impl<T> Indented<T> {
-    pub const fn new(x: T) -> Self {
-        Self { x }
-    }
-}
-impl<T: Display> Display for Indented<T> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut indent_writer = IndentWriter::new(BASE_INDENT, f);
-        write!(indent_writer, "{}", self.x)
-    }
-}
-
-#[derive(Clone, Eq, PartialEq, Debug, Display)]
-#[display("{}", display_list!(_0, "\n"))]
-pub struct TopLevelAssertions<'a>(pub Vec<TopLevelAssertion<'a>>);
-
-impl<'a> TopLevelAssertions<'a> {
-    #[must_use]
-    pub(crate) const fn empty() -> Self {
-        Self(vec![])
-    }
-
-    pub(crate) fn push(&mut self, a: TopLevelAssertion<'a>) {
-        self.0.push(a);
-    }
-}
+/// As such, they may not be suitable for general use.
+pub mod command;
+pub mod module;
+pub mod term;
diff --git a/rr_frontend/radium/src/coq/module.rs b/rr_frontend/radium/src/coq/module.rs
index 598af49..d986f80 100644
--- a/rr_frontend/radium/src/coq/module.rs
+++ b/rr_frontend/radium/src/coq/module.rs
@@ -4,7 +4,7 @@
 // If a copy of the BSD-3-clause license was not distributed with this
 // file, You can obtain one at https://opensource.org/license/bsd-3-clause/.
 
-/// Rocq modules, which contains imports and exports.
+/// Rocq module system.
 use std::fmt;
 use std::ops::Deref;
 
diff --git a/rr_frontend/radium/src/coq/term.rs b/rr_frontend/radium/src/coq/term.rs
new file mode 100644
index 0000000..8c81804
--- /dev/null
+++ b/rr_frontend/radium/src/coq/term.rs
@@ -0,0 +1,414 @@
+// © 2023, The RefinedRust Developers and Contributors
+//
+// This Source Code Form is subject to the terms of the BSD-3-clause License.
+// If a copy of the BSD-3-clause license was not distributed with this
+// file, You can obtain one at https://opensource.org/license/bsd-3-clause/.
+
+/// Rocq terms.
+use std::fmt::{self, Write};
+
+use derive_more::Display;
+use indent_write::fmt::IndentWriter;
+use indent_write::indentable::Indentable;
+use itertools::Itertools;
+
+use crate::{display_list, make_indent, write_list, BASE_INDENT};
+
+/// Represents an application of a term to an rhs.
+/// (commonly used for layouts and instantiating them with generics).
+#[derive(Clone, Eq, PartialEq, Hash, Debug)]
+pub struct App<T, U> {
+    pub(crate) lhs: T,
+    pub(crate) rhs: Vec<U>,
+}
+
+impl<T: Display, U: Display> Display for App<T, U> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.rhs.is_empty() {
+            return write!(f, "{}", self.lhs);
+        }
+
+        write_list!(f, &self.rhs, " ", "({})")
+    }
+}
+
+impl<T, U> App<T, U> {
+    pub fn new(lhs: T, rhs: Vec<U>) -> Self {
+        Self { lhs, rhs }
+    }
+
+    pub fn new_lhs(lhs: T) -> Self {
+        Self {
+            lhs,
+            rhs: Vec::new(),
+        }
+    }
+
+    pub(crate) const fn get_lhs(&self) -> &T {
+        &self.lhs
+    }
+}
+
+/// A Coq Gallina term.
+#[derive(Clone, Eq, PartialEq, Debug)]
+pub enum Gallina {
+    /// a literal
+    Literal(String),
+    /// Application
+    App(Box<App<Gallina, Gallina>>),
+    /// a record body
+    RecordBody(RecordBody),
+    /// Projection a.(b) from a record
+    RecordProj(Box<Gallina>, String),
+    /// Universal quantifiers
+    All(ParamList, Box<Gallina>),
+    /// Existential quantifiers
+    Exists(ParamList, Box<Gallina>),
+    /// Infix operators
+    Infix(String, Vec<Gallina>),
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct RecordBodyItem {
+    pub name: String,
+    pub params: ParamList,
+    pub term: Gallina,
+}
+
+impl Display for RecordBodyItem {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut writer = IndentWriter::new_skip_initial(BASE_INDENT, &mut *f);
+        write!(writer, "{} {} :=\n{};", self.name, self.params, self.term)
+    }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct RecordBody {
+    pub items: Vec<RecordBodyItem>,
+}
+
+impl Display for RecordBody {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{{|\n")?;
+        let mut f2 = IndentWriter::new(BASE_INDENT, &mut *f);
+        for it in &self.items {
+            write!(f2, "{}\n", it)?;
+        }
+        write!(f, "|}}\n")
+    }
+}
+
+impl Display for Gallina {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Literal(lit) => {
+                let mut f2 = IndentWriter::new_skip_initial(BASE_INDENT, &mut *f);
+                write!(f2, "{lit}")
+            },
+            Self::RecordBody(b) => {
+                write!(f, "{b}")
+            },
+            Self::RecordProj(rec, component) => {
+                write!(f, "{rec}.({component})")
+            },
+            Self::App(box a) => write!(f, "{a}"),
+            Self::All(binders, box body) => {
+                if !binders.0.is_empty() {
+                    write!(f, "∀ {binders}, ")?;
+                }
+                write!(f, "{body}")
+            },
+            Self::Exists(binders, box body) => {
+                if !binders.0.is_empty() {
+                    write!(f, "∃ {binders}, ")?;
+                }
+                write!(f, "{body}")
+            },
+            Self::Infix(op, terms) => {
+                if terms.is_empty() {
+                    write!(f, "True")
+                } else {
+                    write!(f, "{}", terms.iter().format(&format!(" {op} ")))
+                }
+            },
+        }
+    }
+}
+
+#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Display)]
+pub enum Name {
+    #[display("{}", _0)]
+    Named(String),
+
+    #[display("_")]
+    Unnamed,
+}
+
+/// A Coq pattern, e.g., "x" or "'(x, y)".
+pub type Pattern = String;
+
+fn fmt_prod(v: &Vec<Type>) -> String {
+    match v.as_slice() {
+        [] => "unit".to_owned(),
+        [t] => t.to_string(),
+        _ => format!("({})%type", display_list!(v, " * ")),
+    }
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+pub enum Type {
+    /// literal types that are not contained in the grammar
+    #[display("{}", _0)]
+    Literal(String),
+
+    /// function types; the argument vector should be non-empty
+    #[display("{} → {}", display_list!(_0, " → ", "({})"), *_1)]
+    Function(Vec<Type>, Box<Type>),
+
+    /// Placeholder that should be inferred by Coq if possible
+    #[display("_")]
+    Infer,
+
+    /// Coq type `lft`
+    #[display("lft")]
+    Lft,
+
+    /// Coq type `loc`
+    #[display("loc")]
+    Loc,
+
+    /// Coq type `layout`
+    #[display("layout")]
+    Layout,
+
+    /// Coq type `syn_type`
+    #[display("syn_type")]
+    SynType,
+
+    /// Coq type `struct_layout`
+    #[display("struct_layout")]
+    StructLayout,
+
+    /// Coq type `Type`
+    #[display("Type")]
+    Type,
+
+    /// Coq type `type rt`
+    #[display("(type {})", &_0)]
+    Ttype(Box<Type>),
+
+    /// Coq type `rtype`
+    #[display("rtype")]
+    Rtype,
+
+    /// the unit type
+    #[display("unit")]
+    Unit,
+
+    /// the type of integers
+    #[display("Z")]
+    Z,
+
+    /// the type of booleans
+    #[display("bool")]
+    Bool,
+
+    /// product types
+    #[display("{}", fmt_prod(_0))]
+    Prod(Vec<Type>),
+
+    /// place_rfn
+    #[display("(place_rfn {})", &_0)]
+    PlaceRfn(Box<Type>),
+
+    /// gname
+    #[display("gname")]
+    Gname,
+
+    /// a plist with a given type constructor over a list of types
+    #[display("plist {} [{}]", _0, display_list!(_1, "; ", "{} : Type"))]
+    PList(String, Vec<Type>),
+
+    /// the semantic type of a function
+    #[display("function_ty")]
+    FunctionTy,
+
+    /// the Coq type Prop of propositions
+    #[display("Prop")]
+    Prop,
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+#[display("{}", self.format(true))]
+pub struct Param {
+    /// the name
+    name: Name,
+
+    /// the type
+    ty: Type,
+
+    /// implicit or not?
+    implicit: bool,
+
+    /// does this depend on Σ?
+    depends_on_sigma: bool,
+}
+
+impl Param {
+    #[must_use]
+    pub fn new(name: Name, ty: Type, implicit: bool) -> Self {
+        let depends_on_sigma = if let Type::Literal(lit) = &ty { lit.contains('Σ') } else { false };
+
+        Self {
+            name,
+            ty,
+            implicit,
+            depends_on_sigma,
+        }
+    }
+
+    #[must_use]
+    pub fn with_name(&self, name: String) -> Self {
+        Self::new(Name::Named(name), self.ty.clone(), self.implicit)
+    }
+
+    #[must_use]
+    pub fn get_name_ref(&self) -> Option<&str> {
+        match &self.name {
+            Name::Named(s) => Some(s),
+            Name::Unnamed => None,
+        }
+    }
+
+    #[allow(clippy::collapsible_else_if)]
+    #[must_use]
+    fn format(&self, make_implicits: bool) -> String {
+        if !self.implicit {
+            return format!("({} : {})", self.name, self.ty);
+        }
+
+        if make_implicits {
+            if let Name::Named(name) = &self.name {
+                format!("`{{{} : !{}}}", name, self.ty)
+            } else {
+                format!("`{{!{}}}", self.ty)
+            }
+        } else {
+            if let Name::Named(name) = &self.name {
+                format!("`({} : !{})", name, self.ty)
+            } else {
+                format!("`(!{})", self.ty)
+            }
+        }
+    }
+
+    pub(crate) const fn get_name(&self) -> &Name {
+        &self.name
+    }
+
+    pub(crate) const fn is_implicit(&self) -> bool {
+        self.implicit
+    }
+
+    pub(crate) const fn is_dependent_on_sigma(&self) -> bool {
+        self.depends_on_sigma
+    }
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+#[display("{}", display_list!(_0, " "))]
+pub struct ParamList(pub Vec<Param>);
+
+impl ParamList {
+    #[must_use]
+    pub const fn new(params: Vec<Param>) -> Self {
+        Self(params)
+    }
+
+    #[must_use]
+    pub const fn empty() -> Self {
+        Self(vec![])
+    }
+
+    pub fn append(&mut self, params: Vec<Param>) {
+        self.0.extend(params);
+    }
+
+    /// Make using terms for this list of binders
+    #[must_use]
+    pub fn make_using_terms(&self) -> Vec<Gallina> {
+        self.0.iter().map(|x| Gallina::Literal(format!("{}", x.name))).collect()
+    }
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+#[display("{} {}", name, params)]
+pub struct Variant {
+    name: String,
+    params: ParamList,
+}
+
+impl Variant {
+    #[must_use]
+    pub fn new(name: &str, params: Vec<Param>) -> Self {
+        Self {
+            name: name.to_owned(),
+            params: ParamList::new(params),
+        }
+    }
+}
+
+#[derive(Clone, Eq, PartialEq, Debug, Display)]
+#[display("Inductive {} {} :=\n{}\n.", name, parameters,
+    display_list!(variants, "\n| ").indented(&make_indent(1))
+)]
+pub struct Inductive {
+    name: String,
+    parameters: ParamList,
+    variants: Vec<Variant>,
+}
+
+impl Inductive {
+    #[must_use]
+    pub fn new(name: &str, parameters: Vec<Param>, variants: Vec<Variant>) -> Self {
+        Self {
+            name: name.to_owned(),
+            parameters: ParamList::new(parameters),
+            variants,
+        }
+    }
+
+    pub(crate) const fn get_name(&self) -> &String {
+        &self.name
+    }
+}
+
+#[derive(Clone, Debug, Display, Eq, PartialEq)]
+#[display("{} {} : {}", name, params, ty)]
+pub struct RecordDeclItem {
+    pub name: String,
+    pub params: ParamList,
+    pub ty: Type,
+}
+
+/// A record declaration.
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Record {
+    pub name: String,
+    pub params: ParamList,
+    pub ty: Type,
+    pub constructor: Option<String>,
+    pub body: Vec<RecordDeclItem>,
+}
+
+impl Display for Record {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let constructor = self.constructor.clone().unwrap_or_default();
+        write!(f, "Record {} {} : {} := {constructor} {{\n", self.name, self.params, self.ty)?;
+        let mut f2 = IndentWriter::new(BASE_INDENT, &mut *f);
+        for it in &self.body {
+            write!(f2, "{it};\n")?;
+        }
+        write!(f, "}}.")
+    }
+}
diff --git a/rr_frontend/radium/src/specs.rs b/rr_frontend/radium/src/specs.rs
index 29410d8..92fef72 100644
--- a/rr_frontend/radium/src/specs.rs
+++ b/rr_frontend/radium/src/specs.rs
@@ -5,7 +5,6 @@
 // file, You can obtain one at https://opensource.org/license/bsd-3-clause/.
 
 /// Provides the Spec AST and utilities for interfacing with it.
-use std::cell::{OnceCell, RefCell};
 use std::collections::{HashMap, HashSet};
 use std::fmt::{Formatter, Write};
 use std::ops::{Add, Range};
@@ -145,9 +144,9 @@ pub enum OpType {
     Char,
     Ptr,
     // a term for the struct_layout, and optypes for the individual fields
-    Struct(coq::AppTerm<String, String>, Vec<OpType>),
+    Struct(coq::term::App<String, String>, Vec<OpType>),
     Untyped(Layout),
-    Literal(coq::AppTerm<String, String>),
+    Literal(coq::term::App<String, String>),
 }
 
 impl Display for OpType {
@@ -214,6 +213,7 @@ impl From<SynType> for Layout {
         Self::from(&x)
     }
 }
+
 impl From<&SynType> for Layout {
     /// Get a Coq term for the layout of this syntactic type.
     /// This may call the Coq-level layout algorithm that we assume.
@@ -230,7 +230,7 @@ impl From<&SynType> for Layout {
 
             SynType::Literal(ca) => {
                 let rhs = ca.to_owned();
-                Self::Literal(coq::AppTerm::new("use_layout_alg'".to_owned(), vec![rhs]))
+                Self::Literal(coq::term::App::new("use_layout_alg'".to_owned(), vec![rhs]))
             },
         }
     }
@@ -254,12 +254,12 @@ impl From<&SynType> for OpType {
             SynType::Ptr | SynType::FnPtr => Self::Ptr,
 
             SynType::Untyped(ly) => Self::Untyped(ly.clone()),
-            SynType::Unit => Self::Struct(coq::AppTerm::new_lhs("unit_sl".to_owned()), Vec::new()),
+            SynType::Unit => Self::Struct(coq::term::App::new_lhs("unit_sl".to_owned()), Vec::new()),
             SynType::Never => Self::Untyped(Layout::Unit),
 
             SynType::Literal(ca) => {
                 let rhs = ca.to_owned();
-                Self::Literal(coq::AppTerm::new("use_op_alg'".to_owned(), vec![rhs]))
+                Self::Literal(coq::term::App::new("use_op_alg'".to_owned(), vec![rhs]))
             },
         }
     }
@@ -318,7 +318,7 @@ pub struct LiteralType {
     /// Coq name of the type
     pub type_term: String,
     /// the refinement type
-    pub refinement_type: coq::Type,
+    pub refinement_type: coq::term::Type,
     /// the syntactic type
     pub syn_type: SynType,
 }
@@ -374,7 +374,7 @@ impl<'def> LiteralTypeUse<'def> {
             self.params.iter().map(|ty| ty.get_rfn_type().to_string()).collect();
 
         let rfn_type = self.def.refinement_type.to_string();
-        let applied = coq::AppTerm::new(rfn_type, rfn_instantiations);
+        let applied = coq::term::App::new(rfn_type, rfn_instantiations);
         applied.to_string()
     }
 
@@ -387,7 +387,7 @@ impl<'def> LiteralTypeUse<'def> {
             let st: SynType = p.into();
             param_sts.push(format!("({})", st));
         }
-        let specialized_spec = coq::AppTerm::new(self.def.syn_type.clone(), param_sts);
+        let specialized_spec = coq::term::App::new(self.def.syn_type.clone(), param_sts);
         SynType::Literal(specialized_spec.to_string())
     }
 
@@ -399,7 +399,7 @@ impl<'def> LiteralTypeUse<'def> {
             let st: SynType = p.into();
             param_sts.push(format!("({})", st));
         }
-        let specialized_spec = coq::AppTerm::new(self.def.syn_type.clone(), param_sts).to_string();
+        let specialized_spec = coq::term::App::new(self.def.syn_type.clone(), param_sts).to_string();
         SynType::Literal(format!("({specialized_spec} : syn_type)"))
     }
 
@@ -410,7 +410,7 @@ impl<'def> LiteralTypeUse<'def> {
         for p in &self.params {
             param_tys.push(format!("({})", p));
         }
-        let specialized_term = coq::AppTerm::new(self.def.type_term.clone(), param_tys);
+        let specialized_term = coq::term::App::new(self.def.type_term.clone(), param_tys);
         specialized_term.to_string()
     }
 }
@@ -466,19 +466,23 @@ impl LiteralTyParam {
         LiteralType {
             rust_name: Some(self.rust_name.clone()),
             type_term: self.type_term.clone(),
-            refinement_type: coq::Type::Literal(self.refinement_type.clone()),
+            refinement_type: coq::term::Type::Literal(self.refinement_type.clone()),
             syn_type: SynType::Literal(self.syn_type.clone()),
         }
     }
 
     #[must_use]
-    pub fn make_refinement_param(&self) -> coq::Param {
-        coq::Param::new(coq::Name::Named(self.refinement_type.clone()), coq::Type::Type, false)
+    pub fn make_refinement_param(&self) -> coq::term::Param {
+        coq::term::Param::new(
+            coq::term::Name::Named(self.refinement_type.clone()),
+            coq::term::Type::Type,
+            false,
+        )
     }
 
     #[must_use]
-    pub fn make_syntype_param(&self) -> coq::Param {
-        coq::Param::new(coq::Name::Named(self.syn_type.clone()), coq::Type::SynType, false)
+    pub fn make_syntype_param(&self) -> coq::term::Param {
+        coq::term::Param::new(coq::term::Name::Named(self.syn_type.clone()), coq::term::Type::SynType, false)
     }
 }
 
@@ -578,28 +582,29 @@ impl<'def> Type<'def> {
 
     /// Determines the type this type is refined by.
     #[must_use]
-    pub fn get_rfn_type(&self) -> coq::Type {
+    pub fn get_rfn_type(&self) -> coq::term::Type {
         match self {
-            Self::Bool => coq::Type::Bool,
-            Self::Char | Self::Int(_) => coq::Type::Z,
+            Self::Bool => coq::term::Type::Bool,
+            Self::Char | Self::Int(_) => coq::term::Type::Z,
 
-            Self::MutRef(box ty, _) => {
-                coq::Type::Prod(vec![coq::Type::PlaceRfn(Box::new(ty.get_rfn_type())), coq::Type::Gname])
-            },
+            Self::MutRef(box ty, _) => coq::term::Type::Prod(vec![
+                coq::term::Type::PlaceRfn(Box::new(ty.get_rfn_type())),
+                coq::term::Type::Gname,
+            ]),
 
             Self::ShrRef(box ty, _) | Self::BoxType(box ty) => {
-                coq::Type::PlaceRfn(Box::new(ty.get_rfn_type()))
+                coq::term::Type::PlaceRfn(Box::new(ty.get_rfn_type()))
             },
 
-            Self::RawPtr => coq::Type::Loc,
+            Self::RawPtr => coq::term::Type::Loc,
 
-            Self::LiteralParam(lit) => coq::Type::Literal(lit.refinement_type.clone()),
-            Self::Literal(lit) => coq::Type::Literal(lit.get_rfn_type()),
+            Self::LiteralParam(lit) => coq::term::Type::Literal(lit.refinement_type.clone()),
+            Self::Literal(lit) => coq::term::Type::Literal(lit.get_rfn_type()),
 
             Self::Struct(su) => {
                 // NOTE: we don't need to subst, due to our invariant that the instantiations for
                 // struct uses are already fully substituted
-                coq::Type::Literal(su.get_rfn_type())
+                coq::term::Type::Literal(su.get_rfn_type())
             },
             Self::Enum(su) => {
                 // similar to structs, we don't need to subst
@@ -608,7 +613,7 @@ impl<'def> Type<'def> {
 
             Self::Unit | Self::Never | Self::Uninit(_) => {
                 // NOTE: could also choose to use an uninhabited type for Never
-                coq::Type::Unit
+                coq::term::Type::Unit
             },
         }
     }
@@ -735,12 +740,12 @@ pub struct InvariantSpec {
     shr_lft_binder: String,
 
     /// the refinement type of this struct
-    rfn_type: coq::Type,
+    rfn_type: coq::term::Type,
     /// the binding pattern for the refinement of this type
-    rfn_pat: coq::Pattern,
+    rfn_pat: coq::term::Pattern,
 
     /// existentials that are introduced in the invariant
-    existentials: Vec<(coq::Name, coq::Type)>,
+    existentials: Vec<(coq::term::Name, coq::term::Type)>,
 
     /// an optional invariant as a separating conjunction,
     invariants: Vec<(IProp, InvariantMode)>,
@@ -748,10 +753,10 @@ pub struct InvariantSpec {
     ty_own_invariants: Vec<TyOwnSpec>,
 
     /// the specification of the abstracted refinement under a context where rfn_pat is bound
-    abstracted_refinement: Option<coq::Pattern>,
+    abstracted_refinement: Option<coq::term::Pattern>,
     // TODO add stuff for non-atomic/atomic invariants
     /// name, type, implicit or not
-    coq_params: Vec<coq::Param>,
+    coq_params: Vec<coq::term::Param>,
 }
 
 impl InvariantSpec {
@@ -760,13 +765,13 @@ impl InvariantSpec {
         type_name: String,
         flags: InvariantSpecFlags,
         shr_lft_binder: String,
-        rfn_type: coq::Type,
-        rfn_pat: coq::Pattern,
-        existentials: Vec<(coq::Name, coq::Type)>,
+        rfn_type: coq::term::Type,
+        rfn_pat: coq::term::Pattern,
+        existentials: Vec<(coq::term::Name, coq::term::Type)>,
         invariants: Vec<(IProp, InvariantMode)>,
         ty_own_invariants: Vec<TyOwnSpec>,
-        abstracted_refinement: Option<coq::Pattern>,
-        coq_params: Vec<coq::Param>,
+        abstracted_refinement: Option<coq::term::Pattern>,
+        coq_params: Vec<coq::term::Param>,
     ) -> Self {
         if flags == InvariantSpecFlags::Persistent {
             assert!(invariants.iter().all(|it| it.1 == InvariantMode::All) && ty_own_invariants.is_empty());
@@ -787,7 +792,7 @@ impl InvariantSpec {
     }
 
     /// Add the abstracted refinement, if it was not already provided.
-    pub fn provide_abstracted_refinement(&mut self, abstracted_refinement: coq::Pattern) {
+    pub fn provide_abstracted_refinement(&mut self, abstracted_refinement: coq::term::Pattern) {
         if self.abstracted_refinement.is_some() {
             panic!("abstracted refinement for {} already provided", self.type_name);
         }
@@ -1048,11 +1053,11 @@ impl InvariantSpec {
         // get the applied base_rfn_type
         let rfn_instantiations: Vec<String> =
             generic_params.iter().map(|names| names.refinement_type.clone()).collect();
-        let applied_base_rfn_type = coq::AppTerm::new(base_rfn_type, rfn_instantiations.clone());
+        let applied_base_rfn_type = coq::term::App::new(base_rfn_type, rfn_instantiations.clone());
 
         // get the applied base type
         let base_type_app: Vec<String> = generic_params.iter().map(|names| names.type_term.clone()).collect();
-        let applied_base_type = coq::AppTerm::new(base_type_name, base_type_app);
+        let applied_base_type = coq::term::App::new(base_type_name, base_type_app);
 
         write!(
             out,
@@ -1157,7 +1162,7 @@ pub struct AbstractVariant<'def> {
     /// the fields, closed under a surrounding scope
     fields: Vec<(String, Type<'def>)>,
     /// the refinement type of the plain struct
-    rfn_type: coq::Type,
+    rfn_type: coq::term::Type,
     /// the struct representation mode
     repr: StructRepr,
     /// the struct's name
@@ -1242,7 +1247,7 @@ impl<'def> AbstractVariant<'def> {
     pub fn generate_coq_type_term(&self, sls_app: Vec<String>) -> String {
         let mut out = String::with_capacity(200);
 
-        out.push_str(&format!("struct_t {} +[", coq::AppTerm::new(&self.sls_def_name, sls_app)));
+        out.push_str(&format!("struct_t {} +[", coq::term::App::new(&self.sls_def_name, sls_app)));
         push_str_list!(out, &self.fields, ";", |(_, ty)| ty.to_string());
         out.push(']');
 
@@ -1303,7 +1308,7 @@ impl<'def> AbstractVariant<'def> {
     pub fn generate_coq_type_def(
         &self,
         ty_params: &[LiteralTyParam],
-        extra_context: &[coq::Param],
+        extra_context: &[coq::term::Param],
     ) -> String {
         let mut out = String::with_capacity(200);
         let indent = "  ";
@@ -1351,7 +1356,10 @@ impl<'def> AbstractVariant<'def> {
     }
 }
 
-fn format_extra_context_items<F>(items: &[coq::Param], f: &mut F) -> Result<(Vec<String>, bool), fmt::Error>
+fn format_extra_context_items<F>(
+    items: &[coq::term::Param],
+    f: &mut F,
+) -> Result<(Vec<String>, bool), fmt::Error>
 where
     F: Write,
 {
@@ -1492,7 +1500,7 @@ impl<'def> AbstractStruct<'def> {
         LiteralType {
             rust_name: Some(self.name().to_owned()),
             type_term: self.public_type_name().to_owned(),
-            refinement_type: coq::Type::Literal(self.public_rt_def_name()),
+            refinement_type: coq::term::Type::Literal(self.public_rt_def_name()),
             syn_type: SynType::Literal(self.sls_def_name().to_owned()),
         }
     }
@@ -1516,7 +1524,7 @@ impl<'def> VariantBuilder<'def> {
         let plain_ty_name: String = format!("{}_ty", &self.name);
         let plain_rt_def_name: String = format!("{}_rt", &self.name);
 
-        let rfn_type = coq::Type::PList(
+        let rfn_type = coq::term::Type::PList(
             "place_rfn".to_owned(),
             self.fields.iter().map(|(_, t)| t.get_rfn_type()).collect(),
         );
@@ -1645,7 +1653,7 @@ impl<'def> AbstractStructUse<'def> {
     #[must_use]
     pub fn get_rfn_type(&self) -> String {
         let Some(def) = self.def.as_ref() else {
-            return coq::Type::Unit.to_string();
+            return coq::term::Type::Unit.to_string();
         };
 
         let rfn_instantiations: Vec<String> =
@@ -1655,11 +1663,11 @@ impl<'def> AbstractStructUse<'def> {
 
         if self.is_raw() || inv.is_none() {
             let rfn_type = def.plain_rt_def_name().to_owned();
-            let applied = coq::AppTerm::new(rfn_type, rfn_instantiations);
+            let applied = coq::term::App::new(rfn_type, rfn_instantiations);
             applied.to_string()
         } else {
             let rfn_type = inv.as_ref().unwrap().rt_def_name();
-            let applied = coq::AppTerm::new(rfn_type, rfn_instantiations);
+            let applied = coq::term::App::new(rfn_type, rfn_instantiations);
             applied.to_string()
         }
     }
@@ -1679,8 +1687,8 @@ impl<'def> AbstractStructUse<'def> {
         }
 
         // use_struct_layout_alg' ([my_spec] [params])
-        let specialized_spec = format!("({})", coq::AppTerm::new(def.sls_def_name(), param_sts));
-        coq::AppTerm::new("use_struct_layout_alg'".to_owned(), vec![specialized_spec]).to_string()
+        let specialized_spec = format!("({})", coq::term::App::new(def.sls_def_name(), param_sts));
+        coq::term::App::new("use_struct_layout_alg'".to_owned(), vec![specialized_spec]).to_string()
     }
 
     #[must_use]
@@ -1698,7 +1706,7 @@ impl<'def> AbstractStructUse<'def> {
         // TODO generates too many apps
 
         // use_struct_layout_alg' ([my_spec] [params])
-        format!("({})", coq::AppTerm::new(def.sls_def_name(), param_sts))
+        format!("({})", coq::term::App::new(def.sls_def_name(), param_sts))
     }
 
     /// Get the `syn_type` term for this struct use.
@@ -1716,7 +1724,7 @@ impl<'def> AbstractStructUse<'def> {
         }
         // TODO generates too many apps
 
-        let specialized_spec = coq::AppTerm::new(def.st_def_name().to_owned(), param_sts);
+        let specialized_spec = coq::term::App::new(def.st_def_name().to_owned(), param_sts);
         SynType::Literal(specialized_spec.to_string())
     }
 
@@ -1737,9 +1745,9 @@ impl<'def> AbstractStructUse<'def> {
                 unreachable!();
             };
 
-            coq::AppTerm::new(inv.type_name.clone(), param_tys).to_string()
+            coq::term::App::new(inv.type_name.clone(), param_tys).to_string()
         } else {
-            coq::AppTerm::new(def.plain_ty_name(), param_tys).to_string()
+            coq::term::App::new(def.plain_ty_name(), param_tys).to_string()
         }
     }
 }
@@ -1748,7 +1756,7 @@ impl<'def> AbstractStructUse<'def> {
 #[derive(Clone, Eq, PartialEq, Debug)]
 pub struct EnumSpec {
     /// the refinement type of the enum
-    pub rfn_type: coq::Type,
+    pub rfn_type: coq::term::Type,
     /// the refinement patterns for each of the variants
     /// eg. for options:
     /// - `(None, [], -[])`
@@ -1789,7 +1797,7 @@ pub struct AbstractEnum<'def> {
     repr: EnumRepr,
 
     /// an optional declaration of a Coq inductive for this enum
-    optional_inductive_def: Option<coq::Inductive>,
+    optional_inductive_def: Option<coq::term::Inductive>,
 
     /// name of the plain enum type (without additional invariants)
     plain_ty_name: String,
@@ -1930,7 +1938,7 @@ impl<'def> AbstractEnum<'def> {
         let spec = &self.spec;
         write!(out, "λ rfn, match rfn with ").unwrap();
         for ((name, _, _), (pat, apps, _)) in self.variants.iter().zip(spec.variant_patterns.iter()) {
-            write!(out, "| {} => \"{name}\" ", coq::AppTerm::new(pat, apps.clone())).unwrap();
+            write!(out, "| {} => \"{name}\" ", coq::term::App::new(pat, apps.clone())).unwrap();
         }
         write!(out, "end").unwrap();
 
@@ -1951,7 +1959,7 @@ impl<'def> AbstractEnum<'def> {
             // environment where all the type parametes are already instantiated.
             let ty = v.public_type_name();
 
-            write!(out, "| {} => existT _ ({ty}, {rfn})", coq::AppTerm::new(pat, apps.clone())).unwrap();
+            write!(out, "| {} => existT _ ({ty}, {rfn})", coq::term::App::new(pat, apps.clone())).unwrap();
         }
         write!(out, " end").unwrap();
 
@@ -2018,7 +2026,7 @@ impl<'def> AbstractEnum<'def> {
                 tag,
                 ty_def_term,
                 res,
-                coq::AppTerm::new(pat, args.clone())
+                coq::term::App::new(pat, args.clone())
             )
             .unwrap();
             write!(out, "{indent}Next Obligation. intros; unfold TCDone in *; naive_solver. Qed.\n").unwrap();
@@ -2082,21 +2090,26 @@ impl<'def> AbstractEnum<'def> {
             writeln!(
                 out,
                 "{}",
-                coq::TopLevelAssertion::Comment(&format!("auto-generated representation of {}", name))
+                coq::command::TopLevelAssertion::Comment(&format!(
+                    "auto-generated representation of {}",
+                    name
+                ))
             )
             .unwrap();
 
-            writeln!(out, "{}", coq::TopLevelAssertion::InductiveDecl(ind)).unwrap();
+            writeln!(out, "{}", coq::command::TopLevelAssertion::InductiveDecl(ind)).unwrap();
 
             // prove that it is inhabited
             writeln!(
                 out,
                 "{}",
-                coq::TopLevelAssertion::InstanceDecl(&coq::InstanceDecl::new(
-                    coq::Type::Literal(format!("Inhabited {}", name)),
-                    coq::DefBody::Script(
-                        coq::ProofScript(vec![coq::ProofItem::Literal("solve_inhabited".to_owned())]),
-                        coq::ProofScriptTerminator::Qed,
+                coq::command::TopLevelAssertion::InstanceDecl(&coq::command::InstanceDecl::new(
+                    coq::term::Type::Literal(format!("Inhabited {}", name)),
+                    coq::command::DefBody::Script(
+                        coq::command::ProofScript(vec![coq::command::ProofItem::Literal(
+                            "solve_inhabited".to_owned()
+                        )]),
+                        coq::command::ProofScriptTerminator::Qed,
                     ),
                 ))
             )
@@ -2110,7 +2123,7 @@ impl<'def> AbstractEnum<'def> {
             let term = format!("(ty_syn_type {})", names.type_term);
             els_app.push(term);
         }
-        let els_app_term = coq::AppTerm::new(&self.els_def_name, els_app);
+        let els_app_term = coq::term::App::new(&self.els_def_name, els_app);
 
         // main def
         write!(
@@ -2169,7 +2182,7 @@ impl<'def> AbstractEnum<'def> {
         LiteralType {
             rust_name: Some(self.name().to_owned()),
             type_term: self.public_type_name().to_owned(),
-            refinement_type: coq::Type::Literal(self.public_rt_def_name().to_owned()),
+            refinement_type: coq::term::Type::Literal(self.public_rt_def_name().to_owned()),
             syn_type: SynType::Literal(self.els_def_name().to_owned()),
         }
     }
@@ -2194,7 +2207,7 @@ impl<'def> EnumBuilder<'def> {
     #[must_use]
     pub fn finish(
         self,
-        optional_inductive_def: Option<coq::Inductive>,
+        optional_inductive_def: Option<coq::term::Inductive>,
         spec: EnumSpec,
     ) -> AbstractEnum<'def> {
         let els_def_name: String = format!("{}_els", &self.name);
@@ -2283,7 +2296,7 @@ impl<'def> AbstractEnumUse<'def> {
     /// Get the refinement type of an enum usage.
     /// This requires that all type parameters of the enum have been instantiated.
     #[must_use]
-    pub fn get_rfn_type(&self) -> coq::Type {
+    pub fn get_rfn_type(&self) -> coq::term::Type {
         self.def.spec.rfn_type.clone()
     }
 
@@ -2298,8 +2311,8 @@ impl<'def> AbstractEnumUse<'def> {
         }
 
         // use_struct_layout_alg' ([my_spec] [params])
-        let specialized_spec = format!("({})", coq::AppTerm::new(self.def.els_def_name.clone(), param_sts));
-        coq::AppTerm::new("use_enum_layout_alg'".to_owned(), vec![specialized_spec]).to_string()
+        let specialized_spec = format!("({})", coq::term::App::new(self.def.els_def_name.clone(), param_sts));
+        coq::term::App::new("use_enum_layout_alg'".to_owned(), vec![specialized_spec]).to_string()
     }
 
     /// Generate a term for the enum layout spec (of type `enum_layout_spec`).
@@ -2313,7 +2326,7 @@ impl<'def> AbstractEnumUse<'def> {
         }
 
         // use_struct_layout_alg' ([my_spec] [params])
-        format!("({})", coq::AppTerm::new(self.def.els_def_name.clone(), param_sts))
+        format!("({})", coq::term::App::new(self.def.els_def_name.clone(), param_sts))
     }
 
     /// Get the `syn_type` term for this enum use.
@@ -2327,7 +2340,7 @@ impl<'def> AbstractEnumUse<'def> {
         }
 
         // [my_spec] [params]
-        let specialized_spec = coq::AppTerm::new(self.def.st_def_name.clone(), param_sts);
+        let specialized_spec = coq::term::App::new(self.def.st_def_name.clone(), param_sts);
         SynType::Literal(specialized_spec.to_string())
     }
 
@@ -2338,7 +2351,7 @@ impl<'def> AbstractEnumUse<'def> {
         for p in &self.ty_params {
             param_tys.push(format!("({})", p));
         }
-        let term = coq::AppTerm::new(self.def.plain_ty_name.clone(), param_tys);
+        let term = coq::term::App::new(self.def.plain_ty_name.clone(), param_tys);
         term.to_string()
     }
 }
@@ -2365,7 +2378,7 @@ pub enum Layout {
     Unit,
 
     /// used for variable layout terms, e.g. for struct layouts or generics
-    Literal(coq::AppTerm<String, String>),
+    Literal(coq::term::App<String, String>),
 
     /// padding of a given number of bytes
     Pad(u32),
@@ -2429,10 +2442,10 @@ impl Layout {
 //   apart when generating them.
 
 #[derive(Clone, Eq, PartialEq, Debug)]
-pub struct CoqBinder(coq::Name, coq::Type);
+pub struct CoqBinder(coq::term::Name, coq::term::Type);
 impl CoqBinder {
     #[must_use]
-    pub const fn new(n: coq::Name, t: coq::Type) -> Self {
+    pub const fn new(n: coq::term::Name, t: coq::term::Type) -> Self {
         Self(n, t)
     }
 }
@@ -2548,7 +2561,7 @@ impl<'def> InnerFunctionSpec<'def> {
     }
 
     #[must_use]
-    pub fn get_params(&self) -> Option<&[(coq::Name, coq::Type)]> {
+    pub fn get_params(&self) -> Option<&[(coq::term::Name, coq::term::Type)]> {
         match self {
             Self::Lit(lit) => Some(&lit.params),
             Self::TraitDefault(_) => None,
@@ -2567,8 +2580,8 @@ pub struct FunctionSpec<T> {
     pub generics: GenericScope,
 
     /// Coq-level parameters the typing statement needs
-    pub early_coq_params: coq::ParamList,
-    pub late_coq_params: coq::ParamList,
+    pub early_coq_params: coq::term::ParamList,
+    pub late_coq_params: coq::term::ParamList,
 
     pub spec: T,
 }
@@ -2591,8 +2604,8 @@ impl<T> FunctionSpec<T> {
             spec_name,
             function_name,
             generics: GenericScope::empty(),
-            early_coq_params: coq::ParamList::empty(),
-            late_coq_params: coq::ParamList::empty(),
+            early_coq_params: coq::term::ParamList::empty(),
+            late_coq_params: coq::term::ParamList::empty(),
             spec,
         }
     }
@@ -2602,8 +2615,8 @@ impl<T> FunctionSpec<T> {
         spec_name: String,
         function_name: String,
         generics: GenericScope,
-        early_params: coq::ParamList,
-        late_params: coq::ParamList,
+        early_params: coq::term::ParamList,
+        late_params: coq::term::ParamList,
         spec: T,
     ) -> Self {
         Self {
@@ -2622,7 +2635,7 @@ impl<T> FunctionSpec<T> {
     }
 
     #[must_use]
-    pub fn get_all_coq_params(&self) -> coq::ParamList {
+    pub fn get_all_coq_params(&self) -> coq::term::ParamList {
         // Important: early parameters should always be first, as they include trait specs.
         // Important: the type parameters should be introduced before late parameters to ensure they are in
         // scope.
@@ -2652,12 +2665,12 @@ impl<'def> Display for FunctionSpec<InnerFunctionSpec<'def>> {
         let mut term = String::with_capacity(100);
         self.spec.write_spec_term(&mut term, &self.generics)?;
 
-        let coq_def = coq::Definition {
+        let coq_def = coq::command::Definition {
             name: self.spec_name.clone(),
             params,
             ty: None,
-            body: coq::DefBody::Term(coq::GallinaTerm::Literal(term)),
-            kind: coq::DefinitionKind::Definition,
+            body: coq::command::DefBody::Term(coq::term::Gallina::Literal(term)),
+            kind: coq::command::DefinitionKind::Definition,
         };
         write!(f, "{coq_def}")
     }
@@ -2668,7 +2681,7 @@ impl<'def> Display for FunctionSpec<InnerFunctionSpec<'def>> {
 /// A function specification below generics.
 #[derive(Clone, Debug)]
 pub struct LiteralFunctionSpec<'def> {
-    pub params: Vec<(coq::Name, coq::Type)>,
+    pub params: Vec<(coq::term::Name, coq::term::Type)>,
 
     /// external lifetime context
     pub elctx: Vec<ExtLftConstr>,
@@ -2680,7 +2693,7 @@ pub struct LiteralFunctionSpec<'def> {
     /// argument types including refinements
     pub args: Vec<TypeWithRef<'def>>,
     /// existential quantifiers for the postcondition
-    pub existentials: Vec<(coq::Name, coq::Type)>,
+    pub existentials: Vec<(coq::term::Name, coq::term::Type)>,
     /// return type
     pub ret: TypeWithRef<'def>,
     /// postcondition as a separating conjunction
@@ -2719,14 +2732,14 @@ impl<'def> LiteralFunctionSpec<'def> {
         out
     }
 
-    fn uncurry_typed_binders<'a, F>(v: F) -> (coq::Pattern, coq::Type)
+    fn uncurry_typed_binders<'a, F>(v: F) -> (coq::term::Pattern, coq::term::Type)
     where
-        F: IntoIterator<Item = &'a (coq::Name, coq::Type)>,
+        F: IntoIterator<Item = &'a (coq::term::Name, coq::term::Type)>,
     {
         let mut v = v.into_iter().peekable();
 
         if v.peek().is_none() {
-            return ("_".to_owned(), coq::Type::Literal("unit".to_owned()));
+            return ("_".to_owned(), coq::term::Type::Literal("unit".to_owned()));
         }
 
         let mut pattern = String::with_capacity(100);
@@ -2751,7 +2764,7 @@ impl<'def> LiteralFunctionSpec<'def> {
         pattern.push(')');
         types.push(')');
 
-        (pattern, coq::Type::Literal(types))
+        (pattern, coq::term::Type::Literal(types))
     }
 
     /// Write the core spec term. Assumes that the coq parameters for the type parameters (as given by
@@ -2810,12 +2823,12 @@ impl<'def> LiteralFunctionSpec<'def> {
 
 #[derive(Debug)]
 pub struct LiteralFunctionSpecBuilder<'def> {
-    params: Vec<(coq::Name, coq::Type)>,
+    params: Vec<(coq::term::Name, coq::term::Type)>,
     elctx: Vec<ExtLftConstr>,
     pre: IProp,
     late_pre: IProp,
     args: Vec<TypeWithRef<'def>>,
-    existential: Vec<(coq::Name, coq::Type)>,
+    existential: Vec<(coq::term::Name, coq::term::Type)>,
     ret: Option<TypeWithRef<'def>>,
     post: IProp,
 
@@ -2842,14 +2855,14 @@ impl<'def> LiteralFunctionSpecBuilder<'def> {
         }
     }
 
-    fn push_coq_name(&mut self, name: &coq::Name) {
-        if let coq::Name::Named(name) = &name {
+    fn push_coq_name(&mut self, name: &coq::term::Name) {
+        if let coq::term::Name::Named(name) = &name {
             self.coq_names.insert(name.to_owned());
         }
     }
 
     /// Adds a (universally-quantified) parameter with a given Coq name for the spec.
-    pub fn add_param(&mut self, name: coq::Name, t: coq::Type) -> Result<(), String> {
+    pub fn add_param(&mut self, name: coq::term::Name, t: coq::term::Type) -> Result<(), String> {
         self.ensure_coq_not_bound(&name)?;
         self.push_coq_name(&name);
         self.params.push((name, t));
@@ -2858,10 +2871,10 @@ impl<'def> LiteralFunctionSpecBuilder<'def> {
 
     /// Add a Coq type annotation for a parameter when no type is currently known.
     /// This can e.g. be used to later on add knowledge about the type of a refinement.
-    pub fn add_param_type_annot(&mut self, name: &coq::Name, t: coq::Type) -> Result<(), String> {
+    pub fn add_param_type_annot(&mut self, name: &coq::term::Name, t: coq::term::Type) -> Result<(), String> {
         for (name0, t0) in &mut self.params {
             if *name0 == *name {
-                if *t0 == coq::Type::Infer {
+                if *t0 == coq::term::Type::Infer {
                     *t0 = t;
                 }
                 return Ok(());
@@ -2878,8 +2891,8 @@ impl<'def> LiteralFunctionSpecBuilder<'def> {
         Ok(())
     }
 
-    fn ensure_coq_not_bound(&self, name: &coq::Name) -> Result<(), String> {
-        if let coq::Name::Named(name) = &name {
+    fn ensure_coq_not_bound(&self, name: &coq::term::Name) -> Result<(), String> {
+        if let coq::term::Name::Named(name) = &name {
             if self.coq_names.contains(name) {
                 return Err(format!("Coq name is already bound: {}", name));
             }
@@ -2953,7 +2966,7 @@ impl<'def> LiteralFunctionSpecBuilder<'def> {
     }
 
     /// Add an existentially-quantified variable to the postcondition.
-    pub fn add_existential(&mut self, name: coq::Name, t: coq::Type) -> Result<(), String> {
+    pub fn add_existential(&mut self, name: coq::term::Name, t: coq::term::Type) -> Result<(), String> {
         self.ensure_coq_not_bound(&name)?;
         self.existential.push((name, t));
         // TODO: if we add some kind of name analysis to postcondition, we need to handle the
@@ -2999,14 +3012,14 @@ pub struct TraitInstanceSpec<'def> {
 #[derive(Constructor, Clone, Debug)]
 pub struct TraitSpecAttrsDecl {
     /// a map of attributes and their types
-    pub attrs: HashMap<String, coq::Type>,
+    pub attrs: HashMap<String, coq::term::Type>,
 }
 
 /// Implementation of the attributes of a trait
 #[derive(Constructor, Clone, Debug)]
 pub struct TraitSpecAttrsInst {
     /// a map of attributes and their implementation
-    pub attrs: HashMap<String, coq::GallinaTerm>,
+    pub attrs: HashMap<String, coq::term::Gallina>,
 }
 
 /// A using occurrence of a trait spec.
@@ -3388,60 +3401,60 @@ impl GenericScope {
 
     /// Get the Coq parameters that need to be in scope for the type parameters of this function.
     #[must_use]
-    fn get_coq_ty_params(&self) -> coq::ParamList {
+    fn get_coq_ty_params(&self) -> coq::term::ParamList {
         let mut ty_coq_params = Vec::new();
         for names in &self.tys {
-            ty_coq_params.push(coq::Param::new(
-                coq::Name::Named(names.refinement_type.clone()),
-                coq::Type::Type,
+            ty_coq_params.push(coq::term::Param::new(
+                coq::term::Name::Named(names.refinement_type.clone()),
+                coq::term::Type::Type,
                 false,
             ));
         }
         for names in &self.tys {
-            ty_coq_params.push(coq::Param::new(
-                coq::Name::Named(names.syn_type.clone()),
-                coq::Type::SynType,
+            ty_coq_params.push(coq::term::Param::new(
+                coq::term::Name::Named(names.syn_type.clone()),
+                coq::term::Type::SynType,
                 false,
             ));
         }
-        coq::ParamList(ty_coq_params)
+        coq::term::ParamList(ty_coq_params)
     }
 
     /// Get the Coq parameters that need to be in scope for the type parameters of this function.
     #[must_use]
-    pub fn get_coq_ty_st_params(&self) -> coq::ParamList {
+    pub fn get_coq_ty_st_params(&self) -> coq::term::ParamList {
         let mut ty_coq_params = Vec::new();
         for names in &self.tys {
             ty_coq_params.push(names.make_syntype_param());
         }
-        coq::ParamList::new(ty_coq_params)
+        coq::term::ParamList::new(ty_coq_params)
     }
 
     /// Get the direct Coq parameters that need to be in scope for the type parameters of this function.
     #[must_use]
-    pub fn get_direct_coq_ty_st_params(&self) -> coq::ParamList {
+    pub fn get_direct_coq_ty_st_params(&self) -> coq::term::ParamList {
         let mut ty_coq_params = Vec::new();
         for names in &self.tys {
             if names.origin == TyParamOrigin::Direct {
                 ty_coq_params.push(names.make_syntype_param());
             }
         }
-        coq::ParamList::new(ty_coq_params)
+        coq::term::ParamList::new(ty_coq_params)
     }
 
     #[must_use]
-    pub fn get_direct_coq_ty_rt_params(&self) -> coq::ParamList {
+    pub fn get_direct_coq_ty_rt_params(&self) -> coq::term::ParamList {
         let mut ty_coq_params = Vec::new();
         for names in &self.tys {
             if names.origin == TyParamOrigin::Direct {
                 ty_coq_params.push(names.make_refinement_param());
             }
         }
-        coq::ParamList::new(ty_coq_params)
+        coq::term::ParamList::new(ty_coq_params)
     }
 
     #[must_use]
-    pub fn get_direct_coq_ty_params(&self) -> coq::ParamList {
+    pub fn get_direct_coq_ty_params(&self) -> coq::term::ParamList {
         let mut rt_params = self.get_direct_coq_ty_rt_params();
         let st_params = self.get_direct_coq_ty_st_params();
         rt_params.append(st_params.0);
@@ -3473,21 +3486,24 @@ fn make_trait_instance<'def>(
     is_base_spec: bool,
     spec_record_name: &str,
     spec_record_params_name: &str,
-) -> Result<coq::TopLevelAssertions<'def>, fmt::Error> {
+) -> Result<coq::command::TopLevelAssertions<'def>, fmt::Error> {
     let mut assertions = Vec::new();
 
     // write the param record decl
     let mut def_rts_params = Vec::new();
     for param in scope.tys.iter().chain(assoc_types) {
-        let rt_param =
-            coq::Param::new(coq::Name::Named(param.refinement_type.clone()), coq::Type::Type, false);
+        let rt_param = coq::term::Param::new(
+            coq::term::Name::Named(param.refinement_type.clone()),
+            coq::term::Type::Type,
+            false,
+        );
         def_rts_params.push(rt_param);
     }
-    let def_rts_params = coq::ParamList::new(def_rts_params);
+    let def_rts_params = coq::term::ParamList::new(def_rts_params);
     let def_rts_params_uses = def_rts_params.make_using_terms();
 
     let param_record_term = if spec.methods.is_empty() {
-        coq::GallinaTerm::Literal(of_trait.spec_record_params_constructor_name())
+        coq::term::Gallina::Literal(of_trait.spec_record_params_constructor_name())
     } else {
         let mut components = Vec::new();
         for (item_name, spec) in &spec.methods {
@@ -3508,56 +3524,67 @@ fn make_trait_instance<'def>(
             // finally pass the associated types
             write_list!(body, &assoc_types, " ", |x| { format!("{}", x.refinement_type) })?;
 
-            let item = coq::RecordBodyItem {
+            let item = coq::term::RecordBodyItem {
                 name: record_item_name,
                 params,
-                term: coq::GallinaTerm::Literal(body),
+                term: coq::term::Gallina::Literal(body),
             };
             components.push(item);
         }
-        let record_body = coq::RecordBodyTerm { items: components };
-        coq::GallinaTerm::RecordBody(record_body)
+        let record_body = coq::term::RecordBody { items: components };
+        coq::term::Gallina::RecordBody(record_body)
     };
-    let param_record_definition = coq::Definition {
+    let param_record_definition = coq::command::Definition {
         name: spec_record_params_name.to_owned(),
         params: def_rts_params,
-        ty: Some(coq::Type::Literal(of_trait.spec_params_record.clone())),
-        body: coq::DefBody::Term(param_record_term),
-        kind: coq::DefinitionKind::Definition,
+        ty: Some(coq::term::Type::Literal(of_trait.spec_params_record.clone())),
+        body: coq::command::DefBody::Term(param_record_term),
+        kind: coq::command::DefinitionKind::Definition,
     };
-    assertions.push(coq::TopLevelAssertion::Definition(param_record_definition));
+    assertions.push(coq::command::TopLevelAssertion::Definition(param_record_definition));
 
     // write the attr record decl, if provided
     let mut attrs_type_rts = Vec::new();
     for param in param_inst.iter().chain(assoc_inst) {
         attrs_type_rts.push(format!("{}", param.get_rfn_type()));
     }
-    let attrs_type = coq::AppTerm::new(of_trait.spec_attrs_record.clone(), attrs_type_rts);
-    let attrs_type = coq::Type::Literal(format!("{attrs_type}"));
+    let attrs_type = coq::term::App::new(of_trait.spec_attrs_record.clone(), attrs_type_rts);
+    let attrs_type = coq::term::Type::Literal(format!("{attrs_type}"));
 
     // write the spec record decl
     let mut def_params = Vec::new();
     // all rts
     for param in scope.tys.iter().chain(assoc_types) {
-        let rt_param =
-            coq::Param::new(coq::Name::Named(param.refinement_type.clone()), coq::Type::Type, false);
+        let rt_param = coq::term::Param::new(
+            coq::term::Name::Named(param.refinement_type.clone()),
+            coq::term::Type::Type,
+            false,
+        );
         def_params.push(rt_param);
     }
     // all sts
     for param in scope.tys.iter().chain(assoc_types) {
-        let st_param = coq::Param::new(coq::Name::Named(param.syn_type.clone()), coq::Type::SynType, false);
+        let st_param = coq::term::Param::new(
+            coq::term::Name::Named(param.syn_type.clone()),
+            coq::term::Type::SynType,
+            false,
+        );
         def_params.push(st_param);
     }
     // then, the attrs. these also get the associated types
     if is_base_spec {
-        def_params.push(coq::Param::new(coq::Name::Named("_ATTRS".to_owned()), attrs_type, false));
+        def_params.push(coq::term::Param::new(
+            coq::term::Name::Named("_ATTRS".to_owned()),
+            attrs_type,
+            false,
+        ));
     }
-    let def_params = coq::ParamList::new(def_params);
+    let def_params = coq::term::ParamList::new(def_params);
 
     // for this, we assume that the semantic type parameters are all in scope
     let body_term = if spec.methods.is_empty() {
         // special-case this, as we cannot use record constructor syntax for empty records
-        coq::GallinaTerm::Literal(format!("@{} _", of_trait.spec_record_constructor_name()))
+        coq::term::Gallina::Literal(format!("@{} _", of_trait.spec_record_constructor_name()))
     } else {
         let mut components = Vec::new();
         for (item_name, spec) in &spec.methods {
@@ -3611,15 +3638,15 @@ fn make_trait_instance<'def>(
             )?;
             write!(body, "→ _))")?;
 
-            let item = coq::RecordBodyItem {
+            let item = coq::term::RecordBodyItem {
                 name: record_item_name,
                 params: direct_params,
-                term: coq::GallinaTerm::Literal(body),
+                term: coq::term::Gallina::Literal(body),
             };
             components.push(item);
         }
-        let record_body = coq::RecordBodyTerm { items: components };
-        coq::GallinaTerm::RecordBody(record_body)
+        let record_body = coq::term::RecordBody { items: components };
+        coq::term::Gallina::RecordBody(record_body)
     };
     // add the surrounding quantifiers over the semantic types
     // TODO
@@ -3632,16 +3659,16 @@ fn make_trait_instance<'def>(
     write_list!(ty_annot, &def_rts_params_uses, " ")?;
     write!(ty_annot, "))")?;
 
-    let definition = coq::Definition {
+    let definition = coq::command::Definition {
         name: spec_record_name.to_owned(),
         params: def_params,
-        ty: Some(coq::Type::Literal(ty_annot)),
-        body: coq::DefBody::Term(coq::GallinaTerm::Literal(term_with_specs)),
-        kind: coq::DefinitionKind::Definition,
+        ty: Some(coq::term::Type::Literal(ty_annot)),
+        body: coq::command::DefBody::Term(coq::term::Gallina::Literal(term_with_specs)),
+        kind: coq::command::DefinitionKind::Definition,
     };
-    assertions.push(coq::TopLevelAssertion::Definition(definition));
+    assertions.push(coq::command::TopLevelAssertion::Definition(definition));
 
-    Ok(coq::TopLevelAssertions(assertions))
+    Ok(coq::command::TopLevelAssertions(assertions))
 }
 
 /// When translating a trait declaration, we should generate this, bundling all the components of
@@ -3652,7 +3679,7 @@ pub struct TraitSpecDecl<'def> {
     pub lit: LiteralTraitSpecRef<'def>,
 
     /// a list of extra things we assume in the Coq context
-    pub extra_coq_context: coq::ParamList,
+    pub extra_coq_context: coq::term::ParamList,
 
     /// The generics this trait uses
     pub generics: GenericScope,
@@ -3684,17 +3711,17 @@ impl<'def> Display for TraitSpecDecl<'def> {
             // params are the rt of the direct type parameters
             let params = item_spec.generics.get_direct_coq_ty_rt_params();
 
-            let item = coq::RecordDeclItem {
+            let item = coq::term::RecordDeclItem {
                 name: record_item_name,
                 params,
-                ty: coq::Type::Type,
+                ty: coq::term::Type::Type,
             };
             record_items.push(item);
         }
-        let spec_param_record = coq::Record {
+        let spec_param_record = coq::term::Record {
             name: self.lit.spec_params_record.clone(),
-            params: coq::ParamList::empty(),
-            ty: coq::Type::Type,
+            params: coq::term::ParamList::empty(),
+            ty: coq::term::Type::Type,
             constructor: Some(spec_param_record_constructor),
             body: record_items,
         };
@@ -3705,9 +3732,9 @@ impl<'def> Display for TraitSpecDecl<'def> {
         for (item_name, item_ty) in &self.attrs.attrs {
             let record_item_name = self.lit.make_spec_attr_name(item_name);
 
-            let item = coq::RecordDeclItem {
+            let item = coq::term::RecordDeclItem {
                 name: record_item_name,
-                params: coq::ParamList::empty(),
+                params: coq::term::ParamList::empty(),
                 ty: item_ty.to_owned(),
             };
             record_items.push(item);
@@ -3715,16 +3742,16 @@ impl<'def> Display for TraitSpecDecl<'def> {
         // this is parametric in the params and associated types
         let mut attr_params = Vec::new();
         for param in self.generics.get_ty_params().iter().chain(self.assoc_types.iter()) {
-            attr_params.push(coq::Param::new(
-                coq::Name::Named(param.refinement_type.clone()),
-                coq::Type::Type,
+            attr_params.push(coq::term::Param::new(
+                coq::term::Name::Named(param.refinement_type.clone()),
+                coq::term::Type::Type,
                 true,
             ));
         }
-        let spec_attr_record = coq::Record {
+        let spec_attr_record = coq::term::Record {
             name: self.lit.spec_attrs_record.clone(),
-            params: coq::ParamList::new(attr_params),
-            ty: coq::Type::Type,
+            params: coq::term::ParamList::new(attr_params),
+            ty: coq::term::Type::Type,
             constructor: Some(spec_attrs_record_constructor.clone()),
             body: record_items,
         };
@@ -3757,22 +3784,22 @@ impl<'def> Display for TraitSpecDecl<'def> {
             write_list!(ty_term, &rt_param_uses, " ")?;
             write!(ty_term, " → fn_params)")?;
 
-            let item = coq::RecordDeclItem {
+            let item = coq::term::RecordDeclItem {
                 name: record_item_name,
                 params,
-                ty: coq::Type::Literal(ty_term),
+                ty: coq::term::Type::Literal(ty_term),
             };
             record_items.push(item);
         }
-        let spec_params = vec![coq::Param::new(
-            coq::Name::Named("_P".to_owned()),
-            coq::Type::Literal(self.lit.spec_params_record.clone()),
+        let spec_params = vec![coq::term::Param::new(
+            coq::term::Name::Named("_P".to_owned()),
+            coq::term::Type::Literal(self.lit.spec_params_record.clone()),
             true,
         )];
-        let spec_record = coq::Record {
+        let spec_record = coq::term::Record {
             name: self.lit.spec_record.clone(),
-            params: coq::ParamList::new(spec_params),
-            ty: coq::Type::Type,
+            params: coq::term::ParamList::new(spec_params),
+            ty: coq::term::Type::Type,
             constructor: Some(spec_record_constructor),
             body: record_items,
         };
@@ -3789,25 +3816,25 @@ impl<'def> Display for TraitSpecDecl<'def> {
         let spec_param_type2 = format!("{} _P2", self.lit.spec_record);
         let spec_incl_params = vec![
             // the two spec params
-            coq::Param::new(
-                coq::Name::Named("_P1".to_owned()),
-                coq::Type::Literal(self.lit.spec_params_record.clone()),
+            coq::term::Param::new(
+                coq::term::Name::Named("_P1".to_owned()),
+                coq::term::Type::Literal(self.lit.spec_params_record.clone()),
                 true,
             ),
-            coq::Param::new(
-                coq::Name::Named("_P2".to_owned()),
-                coq::Type::Literal(self.lit.spec_params_record.clone()),
+            coq::term::Param::new(
+                coq::term::Name::Named("_P2".to_owned()),
+                coq::term::Type::Literal(self.lit.spec_params_record.clone()),
                 true,
             ),
             // the two actual specs
-            coq::Param::new(
-                coq::Name::Named(spec_param_name1.clone()),
-                coq::Type::Literal(spec_param_type1),
+            coq::term::Param::new(
+                coq::term::Name::Named(spec_param_name1.clone()),
+                coq::term::Type::Literal(spec_param_type1),
                 false,
             ),
-            coq::Param::new(
-                coq::Name::Named(spec_param_name2.clone()),
-                coq::Type::Literal(spec_param_type2),
+            coq::term::Param::new(
+                coq::term::Name::Named(spec_param_name2.clone()),
+                coq::term::Type::Literal(spec_param_type2),
                 false,
             ),
         ];
@@ -3815,21 +3842,21 @@ impl<'def> Display for TraitSpecDecl<'def> {
         for (name, decl) in &self.default_spec.methods {
             let param_uses = decl.generics.get_direct_coq_ty_params().make_using_terms();
             let record_item_name = self.lit.make_spec_method_name(name);
-            let incl_term = coq::GallinaTerm::All(
+            let incl_term = coq::term::Gallina::All(
                 decl.generics.get_direct_coq_ty_params(),
-                Box::new(coq::GallinaTerm::App(Box::new(coq::AppTerm::new(
-                    coq::GallinaTerm::Literal("function_subtype".to_owned()),
+                Box::new(coq::term::Gallina::App(Box::new(coq::term::App::new(
+                    coq::term::Gallina::Literal("function_subtype".to_owned()),
                     vec![
-                        coq::GallinaTerm::App(Box::new(coq::AppTerm::new(
-                            coq::GallinaTerm::RecordProj(
-                                Box::new(coq::GallinaTerm::Literal(spec_param_name1.clone())),
+                        coq::term::Gallina::App(Box::new(coq::term::App::new(
+                            coq::term::Gallina::RecordProj(
+                                Box::new(coq::term::Gallina::Literal(spec_param_name1.clone())),
                                 record_item_name.clone(),
                             ),
                             param_uses.clone(),
                         ))),
-                        coq::GallinaTerm::App(Box::new(coq::AppTerm::new(
-                            coq::GallinaTerm::RecordProj(
-                                Box::new(coq::GallinaTerm::Literal(spec_param_name2.clone())),
+                        coq::term::Gallina::App(Box::new(coq::term::App::new(
+                            coq::term::Gallina::RecordProj(
+                                Box::new(coq::term::Gallina::Literal(spec_param_name2.clone())),
                                 record_item_name.clone(),
                             ),
                             param_uses.clone(),
@@ -3839,14 +3866,14 @@ impl<'def> Display for TraitSpecDecl<'def> {
             );
             incls.push(incl_term);
         }
-        let body = coq::GallinaTerm::Infix("∧".to_owned(), incls);
+        let body = coq::term::Gallina::Infix("∧".to_owned(), incls);
 
-        let spec_incl_def = coq::Definition {
+        let spec_incl_def = coq::command::Definition {
             name: spec_incl_name,
-            params: coq::ParamList::new(spec_incl_params),
-            ty: Some(coq::Type::Prop),
-            body: coq::DefBody::Term(body),
-            kind: coq::DefinitionKind::Definition,
+            params: coq::term::ParamList::new(spec_incl_params),
+            ty: Some(coq::term::Type::Prop),
+            body: coq::command::DefBody::Term(body),
+            kind: coq::command::DefinitionKind::Definition,
         };
         write!(f, "{spec_incl_def}\n")?;
 
@@ -3935,7 +3962,7 @@ pub struct TraitImplSpec<'def> {
 impl<'def> TraitImplSpec<'def> {
     /// Generate the definition of the attribute record of this trait impl.
     #[must_use]
-    pub fn generate_attr_decl(&self) -> coq::TopLevelAssertion {
+    pub fn generate_attr_decl(&self) -> coq::command::TopLevelAssertion {
         let attrs = &self.trait_ref.attrs;
         let attrs_name = &self.names.spec_attrs_record;
         let param_inst = &self.trait_ref.params_inst;
@@ -3944,11 +3971,14 @@ impl<'def> TraitImplSpec<'def> {
 
         let mut def_rts_params = Vec::new();
         for param in &self.trait_ref.generics.tys {
-            let rt_param =
-                coq::Param::new(coq::Name::Named(param.refinement_type.clone()), coq::Type::Type, false);
+            let rt_param = coq::term::Param::new(
+                coq::term::Name::Named(param.refinement_type.clone()),
+                coq::term::Type::Type,
+                false,
+            );
             def_rts_params.push(rt_param);
         }
-        let def_rts_params = coq::ParamList::new(def_rts_params);
+        let def_rts_params = coq::term::ParamList::new(def_rts_params);
         let def_rts_params_uses = def_rts_params.make_using_terms();
 
         // write the attr record decl
@@ -3956,33 +3986,33 @@ impl<'def> TraitImplSpec<'def> {
         for param in param_inst.iter().chain(assoc_inst) {
             attrs_type_rts.push(format!("{}", param.get_rfn_type()));
         }
-        let attrs_type = coq::AppTerm::new(of_trait.spec_attrs_record.clone(), attrs_type_rts);
-        let attrs_type = coq::Type::Literal(format!("{attrs_type}"));
+        let attrs_type = coq::term::App::new(of_trait.spec_attrs_record.clone(), attrs_type_rts);
+        let attrs_type = coq::term::Type::Literal(format!("{attrs_type}"));
         let attr_record_term = if attrs.attrs.is_empty() {
-            coq::GallinaTerm::Literal(of_trait.spec_record_attrs_constructor_name())
+            coq::term::Gallina::Literal(of_trait.spec_record_attrs_constructor_name())
         } else {
             let mut components = Vec::new();
             for (attr_name, inst) in &attrs.attrs {
                 let record_item_name = of_trait.make_spec_attr_name(attr_name);
 
-                let item = coq::RecordBodyItem {
+                let item = coq::term::RecordBodyItem {
                     name: record_item_name,
-                    params: coq::ParamList::empty(),
+                    params: coq::term::ParamList::empty(),
                     term: inst.to_owned(),
                 };
                 components.push(item);
             }
-            let record_body = coq::RecordBodyTerm { items: components };
-            coq::GallinaTerm::RecordBody(record_body)
+            let record_body = coq::term::RecordBody { items: components };
+            coq::term::Gallina::RecordBody(record_body)
         };
-        let attr_record_definition = coq::Definition {
+        let attr_record_definition = coq::command::Definition {
             name: attrs_name.to_owned(),
             params: def_rts_params,
             ty: Some(attrs_type),
-            body: coq::DefBody::Term(attr_record_term),
-            kind: coq::DefinitionKind::Definition,
+            body: coq::command::DefBody::Term(attr_record_term),
+            kind: coq::command::DefinitionKind::Definition,
         };
-        coq::TopLevelAssertion::Definition(attr_record_definition)
+        coq::command::TopLevelAssertion::Definition(attr_record_definition)
     }
     /*
     fn generate_proof(&self) -> coq::TopLevelAssertion {
@@ -4016,10 +4046,14 @@ impl<'def> TraitImplSpec<'def> {
 impl<'def> Display for TraitImplSpec<'def> {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         // This relies on all the impl's functions already having been printed
-        write!(f, "{}\n", coq::TopLevelAssertion::SectionStart(self.names.spec_record.clone()))?;
+        write!(f, "{}\n", coq::command::TopLevelAssertion::SectionStart(self.names.spec_record.clone()))?;
         {
             let mut f = IndentWriter::new(BASE_INDENT, &mut *f);
-            write!(f, "{}\n", coq::TopLevelAssertion::ContextDecl(coq::ContextDecl::refinedrust()))?;
+            write!(
+                f,
+                "{}\n",
+                coq::command::TopLevelAssertion::ContextDecl(coq::command::ContextDecl::refinedrust())
+            )?;
 
             // write the bundled records
             let base_decls = make_trait_instance(
@@ -4036,7 +4070,7 @@ impl<'def> Display for TraitImplSpec<'def> {
             write!(f, "{base_decls}\n")?;
         }
 
-        write!(f, "{}\n", coq::TopLevelAssertion::SectionEnd(self.names.spec_record.clone()))
+        write!(f, "{}\n", coq::command::TopLevelAssertion::SectionEnd(self.names.spec_record.clone()))
     }
 }
 
@@ -4083,7 +4117,7 @@ impl<'def> InstantiatedTraitFunctionSpec<'def> {
         params.push(self.trait_attr_term.clone());
 
         let mut applied_base_spec = String::with_capacity(100);
-        write!(applied_base_spec, "{}", coq::AppTerm::new(&self.trait_ref.of_trait.base_spec, params))?;
+        write!(applied_base_spec, "{}", coq::term::App::new(&self.trait_ref.of_trait.base_spec, params))?;
         // instantiate semantic types
         for ty in &self.trait_ref.params_inst {
             write!(applied_base_spec, " <TY> {ty}")?;
diff --git a/rr_frontend/translation/src/function_body.rs b/rr_frontend/translation/src/function_body.rs
index 58813df..38a7d6a 100644
--- a/rr_frontend/translation/src/function_body.rs
+++ b/rr_frontend/translation/src/function_body.rs
@@ -1161,13 +1161,11 @@ impl<'a, 'def: 'a, 'tcx: 'def> FunctionTranslator<'a, 'def, 'tcx> {
                 for ty in &assoc_tys {
                     param_ty_args.push(format!("{}", ty.get_rfn_type()));
                 }
-                let param_ty = format!(
-                    "{}",
-                    radium::coq::AppTerm::new(trait_ref.spec_attrs_record.clone(), param_ty_args)
-                );
-                let param = radium::coq::Param::new(
-                    radium::coq::Name::Named(param_name.clone()),
-                    radium::coq::Type::Literal(param_ty),
+                let param_ty =
+                    format!("{}", coq::term::App::new(trait_ref.spec_attrs_record.clone(), param_ty_args));
+                let param = coq::term::Param::new(
+                    coq::term::Name::Named(param_name.clone()),
+                    coq::term::Type::Literal(param_ty),
                     false,
                 );
 
@@ -1196,7 +1194,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> FunctionTranslator<'a, 'def, 'tcx> {
                     for ty in impl_ref.get_trait_param_inst().iter().chain(impl_ref.get_trait_assoc_inst()) {
                         param_ty_args.push(format!("{}", ty.get_rfn_type()));
                     }
-                    let param_ty = format!("{}", radium::coq::AppTerm::new(trait_ref.spec_attrs_record.clone(), param_ty_args));
+                    let param_ty = format!("{}", radium::coq::App::new(trait_ref.spec_attrs_record.clone(), param_ty_args));
                     let param = radium::coq::Param::new(radium::coq::Name::Named(param_name.clone()), radium::coq::Type::Literal(param_ty), false);
 
                     // add it as parameter to the function after the generics
@@ -2127,13 +2125,13 @@ impl<'a, 'def: 'a, 'tcx: 'def> BodyTranslator<'a, 'def, 'tcx> {
             // get the refinement type
             let mut rfn_ty = ty.get_rfn_type();
             // wrap it in place_rfn, since we reason about places
-            rfn_ty = coq::Type::PlaceRfn(Box::new(rfn_ty));
+            rfn_ty = coq::term::Type::PlaceRfn(Box::new(rfn_ty));
 
             // determine their initialization status
             //let initialized = true; // TODO
             // determine the actual refinement type for the current initialization status.
 
-            let rfn_name = coq::Name::Named(format!("r_{}", name));
+            let rfn_name = coq::term::Name::Named(format!("r_{}", name));
             rfn_binders.push(radium::specs::CoqBinder::new(rfn_name, rfn_ty));
         }
 
@@ -3798,7 +3796,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> BodyTranslator<'a, 'def, 'tcx> {
                             translated_ops.into_iter().enumerate().map(|(i, o)| (i.to_string(), o)).collect();
 
                         Ok(radium::Expr::StructInitE {
-                            sls: coq::AppTerm::new_lhs(sl.to_string()),
+                            sls: coq::term::App::new_lhs(sl.to_string()),
                             components: initializers,
                         })
                     },
@@ -3824,7 +3822,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> BodyTranslator<'a, 'def, 'tcx> {
                                 .collect();
 
                             return Ok(radium::Expr::StructInitE {
-                                sls: coq::AppTerm::new_lhs(sl.to_string()),
+                                sls: coq::term::App::new_lhs(sl.to_string()),
                                 components: initializers,
                             });
                         }
@@ -3843,7 +3841,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> BodyTranslator<'a, 'def, 'tcx> {
                                 .collect();
 
                             let variant_e = radium::Expr::StructInitE {
-                                sls: coq::AppTerm::new_lhs(sl.to_string()),
+                                sls: coq::term::App::new_lhs(sl.to_string()),
                                 components: initializers,
                             };
 
@@ -3855,7 +3853,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> BodyTranslator<'a, 'def, 'tcx> {
                             let variant_name = variant_def.name.to_string();
 
                             return Ok(radium::Expr::EnumInitE {
-                                els: coq::AppTerm::new_lhs(els.to_string()),
+                                els: coq::term::App::new_lhs(els.to_string()),
                                 variant: variant_name,
                                 ty,
                                 initializer: Box::new(variant_e),
@@ -3887,7 +3885,7 @@ impl<'a, 'def: 'a, 'tcx: 'def> BodyTranslator<'a, 'def, 'tcx> {
                             translated_ops.into_iter().enumerate().map(|(i, o)| (i.to_string(), o)).collect();
 
                         Ok(radium::Expr::StructInitE {
-                            sls: coq::AppTerm::new_lhs(sl.to_string()),
+                            sls: coq::term::App::new_lhs(sl.to_string()),
                             components: initializers,
                         })
                     },
diff --git a/rr_frontend/translation/src/lib.rs b/rr_frontend/translation/src/lib.rs
index 23d7ff6..440a47c 100644
--- a/rr_frontend/translation/src/lib.rs
+++ b/rr_frontend/translation/src/lib.rs
@@ -997,7 +997,7 @@ fn register_shims<'tcx>(vcx: &mut VerificationCtxt<'tcx, '_>) -> Result<(), base
             rust_name: None,
             type_term: shim.sem_type.clone(),
             syn_type: radium::SynType::Literal(shim.syn_type.clone()),
-            refinement_type: coq::Type::Literal(shim.refinement_type.clone()),
+            refinement_type: coq::term::Type::Literal(shim.refinement_type.clone()),
         };
 
         if let Err(e) = vcx.type_translator.register_adt_shim(did, &lit) {
diff --git a/rr_frontend/translation/src/spec_parsers/crate_attr_parser.rs b/rr_frontend/translation/src/spec_parsers/crate_attr_parser.rs
index 0e1ff2e..fb6dcf4 100644
--- a/rr_frontend/translation/src/spec_parsers/crate_attr_parser.rs
+++ b/rr_frontend/translation/src/spec_parsers/crate_attr_parser.rs
@@ -5,7 +5,7 @@
 // file, You can obtain one at https://opensource.org/license/bsd-3-clause/.
 
 use attribute_parse::parse;
-use radium::{coq, specs};
+use radium::coq;
 use rr_rustc_interface::ast::ast::AttrItem;
 
 use crate::spec_parsers::parse_utils::{self, str_err};
@@ -23,7 +23,7 @@ pub struct CrateAttrs {
     pub prefix: Option<String>,
     pub includes: Vec<String>,
     pub package: Option<String>,
-    pub context_params: Vec<coq::Param>,
+    pub context_params: Vec<coq::term::Param>,
 }
 
 #[allow(clippy::module_name_repetitions)]
@@ -77,9 +77,9 @@ impl CrateAttrParser for VerboseCrateAttrParser {
                 },
                 "context" => {
                     let param: parse_utils::RRGlobalCoqContextItem = buffer.parse(&()).map_err(str_err)?;
-                    context_params.push(coq::Param::new(
-                        coq::Name::Unnamed,
-                        coq::Type::Literal(param.item),
+                    context_params.push(coq::term::Param::new(
+                        coq::term::Name::Unnamed,
+                        coq::term::Type::Literal(param.item),
                         true,
                     ));
                 },
diff --git a/rr_frontend/translation/src/spec_parsers/enum_spec_parser.rs b/rr_frontend/translation/src/spec_parsers/enum_spec_parser.rs
index 7a8eee1..e64f1ae 100644
--- a/rr_frontend/translation/src/spec_parsers/enum_spec_parser.rs
+++ b/rr_frontend/translation/src/spec_parsers/enum_spec_parser.rs
@@ -7,7 +7,7 @@
 use std::collections::HashMap;
 
 use attribute_parse::{parse, MToken};
-use parse::{Parse, Peek};
+use parse::Peek;
 use radium::{coq, specs};
 use rr_rustc_interface::ast::ast::{AttrArgs, AttrItem};
 
@@ -101,7 +101,7 @@ impl<'b, T: ParamLookup> EnumSpecParser for VerboseEnumSpecParser<'b, T> {
                 "refined_by" => {
                     let ty: parse::LitStr = buffer.parse(self.scope).map_err(str_err)?;
                     let (ty, _) = process_coq_literal(ty.value().as_str(), self.scope);
-                    rfn_type = Some(coq::Type::Literal(ty));
+                    rfn_type = Some(coq::term::Type::Literal(ty));
                 },
                 "export_as" => {},
                 _ => {
diff --git a/rr_frontend/translation/src/spec_parsers/module_attr_parser.rs b/rr_frontend/translation/src/spec_parsers/module_attr_parser.rs
index 0850c50..ce6aae8 100644
--- a/rr_frontend/translation/src/spec_parsers/module_attr_parser.rs
+++ b/rr_frontend/translation/src/spec_parsers/module_attr_parser.rs
@@ -5,7 +5,7 @@
 // file, You can obtain one at https://opensource.org/license/bsd-3-clause/.
 
 use attribute_parse::parse;
-use radium::{coq, specs};
+use radium::coq;
 use rr_rustc_interface::ast::ast::AttrItem;
 use rr_rustc_interface::hir::def_id::LocalDefId;
 
@@ -26,7 +26,7 @@ pub trait ModuleAttrParser {
 pub struct ModuleAttrs {
     pub exports: Vec<coq::module::Export>,
     pub includes: Vec<String>,
-    pub context_params: Vec<coq::Param>,
+    pub context_params: Vec<coq::term::Param>,
 }
 
 #[allow(clippy::module_name_repetitions)]
@@ -68,9 +68,9 @@ impl ModuleAttrParser for VerboseModuleAttrParser {
                 },
                 "context" => {
                     let param: parse_utils::RRGlobalCoqContextItem = buffer.parse(&()).map_err(str_err)?;
-                    context_params.push(coq::Param::new(
-                        coq::Name::Unnamed,
-                        coq::Type::Literal(param.item),
+                    context_params.push(coq::term::Param::new(
+                        coq::term::Name::Unnamed,
+                        coq::term::Type::Literal(param.item),
                         true,
                     ));
                 },
diff --git a/rr_frontend/translation/src/spec_parsers/parse_utils.rs b/rr_frontend/translation/src/spec_parsers/parse_utils.rs
index 69a15fb..aca62c3 100644
--- a/rr_frontend/translation/src/spec_parsers/parse_utils.rs
+++ b/rr_frontend/translation/src/spec_parsers/parse_utils.rs
@@ -4,13 +4,13 @@
 // If a copy of the BSD-3-clause license was not distributed with this
 // file, You can obtain one at https://opensource.org/license/bsd-3-clause/.
 
+/// This provides some general utilities for RefinedRust-specific attribute parsing.
 use std::collections::{HashMap, HashSet};
 
 use attribute_parse::{parse, MToken};
 use lazy_static::lazy_static;
 use log::info;
 use parse::{Parse, Peek};
-/// This provides some general utilities for RefinedRust-specific attribute parsing.
 use radium::{coq, specs};
 use regex::{self, Captures, Regex};
 
@@ -132,13 +132,13 @@ impl<T: ParamLookup> parse::Parse<T> for IProp {
 
 /// Parse a Coq type.
 pub struct RRCoqType {
-    pub ty: coq::Type,
+    pub ty: coq::term::Type,
 }
 impl<T: ParamLookup> parse::Parse<T> for RRCoqType {
     fn parse(input: parse::Stream, meta: &T) -> parse::Result<Self> {
         let ty: parse::LitStr = input.parse(meta)?;
         let (ty, _) = process_coq_literal(&ty.value(), meta);
-        let ty = coq::Type::Literal(ty);
+        let ty = coq::term::Type::Literal(ty);
         Ok(Self { ty })
     }
 }
@@ -150,14 +150,14 @@ impl<T: ParamLookup> parse::Parse<T> for RRCoqType {
 /// `w : "(Z * Z)%type"`
 #[derive(Debug)]
 pub struct RRParam {
-    pub name: coq::Name,
-    pub ty: coq::Type,
+    pub name: coq::term::Name,
+    pub ty: coq::term::Type,
 }
 
 impl<T: ParamLookup> parse::Parse<T> for RRParam {
     fn parse(input: parse::Stream, meta: &T) -> parse::Result<Self> {
         let name: IdentOrTerm = input.parse(meta)?;
-        let name = coq::Name::Named(name.to_string());
+        let name = coq::term::Name::Named(name.to_string());
 
         if parse::Colon::peek(input) {
             input.parse::<_, MToken![:]>(meta)?;
@@ -166,7 +166,7 @@ impl<T: ParamLookup> parse::Parse<T> for RRParam {
         } else {
             Ok(Self {
                 name,
-                ty: coq::Type::Infer,
+                ty: coq::term::Type::Infer,
             })
         }
     }
diff --git a/rr_frontend/translation/src/spec_parsers/struct_spec_parser.rs b/rr_frontend/translation/src/spec_parsers/struct_spec_parser.rs
index c1827ea..f662a3f 100644
--- a/rr_frontend/translation/src/spec_parsers/struct_spec_parser.rs
+++ b/rr_frontend/translation/src/spec_parsers/struct_spec_parser.rs
@@ -38,8 +38,8 @@ pub trait InvariantSpecParser {
 /// Parse a binder pattern with an optional Coq type annotation, e.g.
 /// `"(x, y)" : "(Z * Z)%type"`
 struct RfnPattern {
-    rfn_pat: coq::Pattern,
-    rfn_type: Option<coq::Type>,
+    rfn_pat: coq::term::Pattern,
+    rfn_type: Option<coq::term::Type>,
 }
 
 impl<T: ParamLookup> parse::Parse<T> for RfnPattern {
@@ -54,7 +54,7 @@ impl<T: ParamLookup> parse::Parse<T> for RfnPattern {
             let (ty, _) = process_coq_literal(ty.value().as_str(), meta);
             Ok(Self {
                 rfn_pat: pat,
-                rfn_type: Some(coq::Type::Literal(ty)),
+                rfn_type: Some(coq::term::Type::Literal(ty)),
             })
         } else {
             Ok(Self {
@@ -196,14 +196,14 @@ impl<'b, T: ParamLookup> InvariantSpecParser for VerboseInvariantSpecParser<'b,
         let mut abstracted_refinement = None;
 
         let mut rfn_pat = "placeholder_pat".to_owned();
-        let mut rfn_type = coq::Type::Infer;
+        let mut rfn_type = coq::term::Type::Infer;
 
         let mut existentials: Vec<RRParam> = Vec::new();
 
         // use Plain as the default
         let mut inv_flags = specs::InvariantSpecFlags::Plain;
 
-        let mut params: Vec<coq::Param> = Vec::new();
+        let mut params: Vec<coq::term::Param> = Vec::new();
 
         for &it in attrs {
             let path_segs = &it.path.segments;
@@ -270,7 +270,11 @@ impl<'b, T: ParamLookup> InvariantSpecParser for VerboseInvariantSpecParser<'b,
                 "context" => {
                     let param = RRCoqContextItem::parse(&buffer, self.scope).map_err(str_err)?;
 
-                    params.push(coq::Param::new(coq::Name::Unnamed, coq::Type::Literal(param.item), true));
+                    params.push(coq::term::Param::new(
+                        coq::term::Name::Unnamed,
+                        coq::term::Type::Literal(param.item),
+                        true,
+                    ));
                 },
                 _ => {
                     //skip, this may be part of an enum spec
@@ -334,7 +338,7 @@ where
 
     make_literal: F,
     //ty_scope: &'a [Option<specs::Type<'def>>],
-    //rfnty_scope: &'a [Option<coq::Type>],
+    //rfnty_scope: &'a [Option<coq::term::Type>],
 }
 
 impl<'a, 'def, T: ParamLookup, F> VerboseStructFieldSpecParser<'a, 'def, T, F>
@@ -367,7 +371,7 @@ where
         let lit_ty = specs::LiteralType {
             rust_name: None,
             type_term: lit.ty.clone(),
-            refinement_type: coq::Type::Infer,
+            refinement_type: coq::term::Type::Infer,
             syn_type: ty.into(),
         };
         let lit_ref = (self.make_literal)(lit_ty);
diff --git a/rr_frontend/translation/src/spec_parsers/trait_attr_parser.rs b/rr_frontend/translation/src/spec_parsers/trait_attr_parser.rs
index 33f0c73..8850176 100644
--- a/rr_frontend/translation/src/spec_parsers/trait_attr_parser.rs
+++ b/rr_frontend/translation/src/spec_parsers/trait_attr_parser.rs
@@ -8,6 +8,7 @@ use std::collections::HashMap;
 
 use attribute_parse::{parse, MToken};
 use derive_more::Constructor;
+use radium::coq;
 use rr_rustc_interface::ast::ast::AttrItem;
 use rr_rustc_interface::hir::def_id::LocalDefId;
 
@@ -48,7 +49,7 @@ impl<'a, T: ParamLookup> ParamLookup for TraitAttrScope<'a, T> {
 #[derive(Clone, Debug)]
 pub struct TraitAttrs {
     pub attrs: radium::TraitSpecAttrsDecl,
-    pub context_items: Vec<radium::coq::Param>,
+    pub context_items: Vec<coq::term::Param>,
 }
 
 #[allow(clippy::module_name_repetitions)]
@@ -107,9 +108,9 @@ where
                 },
                 "context" => {
                     let context_item: RRCoqContextItem = buffer.parse(&self.scope).map_err(str_err)?;
-                    let param = radium::coq::Param::new(
-                        radium::coq::Name::Unnamed,
-                        radium::coq::Type::Literal(context_item.item),
+                    let param = coq::term::Param::new(
+                        coq::term::Name::Unnamed,
+                        coq::term::Type::Literal(context_item.item),
                         true,
                     );
                     context_items.push(param);
diff --git a/rr_frontend/translation/src/spec_parsers/trait_impl_attr_parser.rs b/rr_frontend/translation/src/spec_parsers/trait_impl_attr_parser.rs
index 5dfe604..35ad963 100644
--- a/rr_frontend/translation/src/spec_parsers/trait_impl_attr_parser.rs
+++ b/rr_frontend/translation/src/spec_parsers/trait_impl_attr_parser.rs
@@ -58,7 +58,7 @@ impl<'b, T: ParamLookup> TraitImplAttrParser for VerboseTraitImplAttrParser<'b,
                     let parsed_term: parse::LitStr = buffer.parse(self.scope).map_err(str_err)?;
                     let (parsed_term, _) = process_coq_literal(&parsed_term.value(), self.scope);
                     if trait_attrs
-                        .insert(parsed_name.to_string(), radium::coq::GallinaTerm::Literal(parsed_term))
+                        .insert(parsed_name.to_string(), radium::coq::term::Gallina::Literal(parsed_term))
                         .is_some()
                     {
                         return Err(format!(
diff --git a/rr_frontend/translation/src/spec_parsers/verbose_function_spec_parser.rs b/rr_frontend/translation/src/spec_parsers/verbose_function_spec_parser.rs
index cdd7cad..94c71b1 100644
--- a/rr_frontend/translation/src/spec_parsers/verbose_function_spec_parser.rs
+++ b/rr_frontend/translation/src/spec_parsers/verbose_function_spec_parser.rs
@@ -245,9 +245,9 @@ pub struct VerboseFunctionSpecParser<'a, 'def, F, T> {
 #[derive(Default)]
 pub struct FunctionRequirements {
     /// additional late coq parameters
-    pub late_coq_params: Vec<coq::Param>,
+    pub late_coq_params: Vec<coq::term::Param>,
     /// additional early coq parameters
-    pub early_coq_params: Vec<coq::Param>,
+    pub early_coq_params: Vec<coq::term::Param>,
     /// proof information
     pub proof_info: ProofInfo,
 }
@@ -296,7 +296,7 @@ where
         &mut self,
         lit: &LiteralTypeWithRef,
         ty: &specs::Type<'def>,
-    ) -> (specs::TypeWithRef<'def>, Option<coq::Type>) {
+    ) -> (specs::TypeWithRef<'def>, Option<coq::term::Type>) {
         if let Some(lit_ty) = &lit.ty {
             // literal type given, we use this literal type as the RR semantic type
             // TODO: get CoqType for refinement. maybe have it as an annotation? the Infer is currently a
@@ -305,7 +305,7 @@ where
             let lit_ty = specs::LiteralType {
                 rust_name: None,
                 type_term: lit_ty.to_string(),
-                refinement_type: coq::Type::Infer,
+                refinement_type: coq::term::Type::Infer,
                 syn_type: ty.into(),
             };
             let lit_ref = (self.make_literal)(lit_ty);
@@ -364,7 +364,7 @@ where
                         // potentially add a typing hint to the refinement
                         if let IdentOrTerm::Ident(i) = arg.rfn {
                             info!("Trying to add a typing hint for {}", i);
-                            builder.add_param_type_annot(&coq::Name::Named(i.clone()), cty)?;
+                            builder.add_param_type_annot(&coq::term::Name::Named(i.clone()), cty)?;
                         }
                     }
                 }
@@ -413,7 +413,11 @@ where
             },
             "context" => {
                 let context_item = RRCoqContextItem::parse(buffer, scope).map_err(str_err)?;
-                let param = coq::Param::new(coq::Name::Unnamed, coq::Type::Literal(context_item.item), true);
+                let param = coq::term::Param::new(
+                    coq::term::Name::Unnamed,
+                    coq::term::Type::Literal(context_item.item),
+                    true,
+                );
                 if context_item.at_end {
                     self.fn_requirements.late_coq_params.push(param);
                 } else {
@@ -534,7 +538,7 @@ where
 
         // push everything to the builder
         for x in new_ghost_vars {
-            builder.add_param(coq::Name::Named(x), coq::Type::Gname).unwrap();
+            builder.add_param(coq::term::Name::Named(x), coq::term::Type::Gname).unwrap();
         }
 
         // assemble a string for the closure arg
@@ -582,7 +586,9 @@ where
             ty::ClosureKind::FnMut => {
                 // wrap the argument in a mutable reference
                 let post_name = "__γclos";
-                builder.add_param(coq::Name::Named(post_name.to_owned()), coq::Type::Gname).unwrap();
+                builder
+                    .add_param(coq::term::Name::Named(post_name.to_owned()), coq::term::Type::Gname)
+                    .unwrap();
 
                 let lft = meta.closure_lifetime.unwrap();
                 let ref_ty = specs::Type::MutRef(Box::new(tuple), lft);
diff --git a/rr_frontend/translation/src/trait_registry.rs b/rr_frontend/translation/src/trait_registry.rs
index fc1fcca..34b8726 100644
--- a/rr_frontend/translation/src/trait_registry.rs
+++ b/rr_frontend/translation/src/trait_registry.rs
@@ -327,7 +327,7 @@ impl<'tcx, 'def> TraitRegistry<'tcx, 'def> {
         let base_instance_spec = radium::TraitInstanceSpec::new(methods);
         let decl = radium::TraitSpecDecl::new(
             lit_trait_spec_ref,
-            radium::coq::ParamList::new(trait_spec.context_items),
+            coq::term::ParamList::new(trait_spec.context_items),
             param_scope.into(),
             assoc_types,
             base_instance_spec,
@@ -466,8 +466,7 @@ impl<'tcx, 'def> TraitRegistry<'tcx, 'def> {
             for ty in &all_impl_args {
                 args.push(format!("{}", ty.get_rfn_type()));
             }
-            let attr_term =
-                format!("{}", radium::coq::AppTerm::new(impl_spec.spec_attrs_record.clone(), args));
+            let attr_term = format!("{}", coq::term::App::new(impl_spec.spec_attrs_record.clone(), args));
 
             radium::SpecializedTraitSpec::new_with_params(
                 impl_spec.spec_record.clone(),
diff --git a/rr_frontend/translation/src/type_translator.rs b/rr_frontend/translation/src/type_translator.rs
index 9183874..2cd27b8 100644
--- a/rr_frontend/translation/src/type_translator.rs
+++ b/rr_frontend/translation/src/type_translator.rs
@@ -1549,7 +1549,7 @@ impl<'def, 'tcx: 'def> TypeTranslator<'def, 'tcx> {
     /// Get the spec for a built-in enum like `std::option::Option`.
     fn get_builtin_enum_spec(&self, did: DefId) -> Option<radium::EnumSpec> {
         let option_spec = radium::EnumSpec {
-            rfn_type: coq::Type::Literal("_".to_owned()),
+            rfn_type: coq::term::Type::Literal("_".to_owned()),
             variant_patterns: vec![
                 ("None".to_owned(), vec![], "-[]".to_owned()),
                 ("Some".to_owned(), vec!["x".to_owned()], "-[x]".to_owned()),
@@ -1557,7 +1557,7 @@ impl<'def, 'tcx: 'def> TypeTranslator<'def, 'tcx> {
         };
 
         let enum_spec = radium::EnumSpec {
-            rfn_type: coq::Type::Literal("_".to_owned()),
+            rfn_type: coq::term::Type::Literal("_".to_owned()),
             variant_patterns: vec![
                 ("inl".to_owned(), vec!["x".to_owned()], "-[x]".to_owned()),
                 ("inr".to_owned(), vec!["x".to_owned()], "-[x]".to_owned()),
@@ -1586,10 +1586,10 @@ impl<'def, 'tcx: 'def> TypeTranslator<'def, 'tcx> {
         &self,
         def: ty::AdtDef<'tcx>,
         inductive_name: String,
-    ) -> (coq::Inductive, radium::EnumSpec) {
+    ) -> (coq::term::Inductive, radium::EnumSpec) {
         trace!("Generating Inductive for enum {:?}", def);
 
-        let mut variants: Vec<coq::Variant> = Vec::new();
+        let mut variants: Vec<coq::term::Variant> = Vec::new();
         let mut variant_patterns = Vec::new();
 
         for v in def.variants() {
@@ -1602,22 +1602,25 @@ impl<'def, 'tcx: 'def> TypeTranslator<'def, 'tcx> {
             let (variant_args, variant_arg_binders, variant_rfn) = if variant_def.fields.is_empty() {
                 (vec![], vec![], "-[]".to_owned())
             } else {
-                let args =
-                    vec![coq::Param::new(coq::Name::Unnamed, coq::Type::Literal(refinement_type), false)];
+                let args = vec![coq::term::Param::new(
+                    coq::term::Name::Unnamed,
+                    coq::term::Type::Literal(refinement_type),
+                    false,
+                )];
 
                 (args, vec!["x".to_owned()], "x".to_owned())
             };
 
-            variants.push(coq::Variant::new(variant_name, variant_args));
+            variants.push(coq::term::Variant::new(variant_name, variant_args));
 
             variant_patterns.push((variant_name.to_string(), variant_arg_binders, variant_rfn));
         }
 
         // We assume the generated Inductive def is placed in a context where the generic types are in scope.
-        let inductive = coq::Inductive::new(&inductive_name, vec![], variants);
+        let inductive = coq::term::Inductive::new(&inductive_name, vec![], variants);
 
         let enum_spec = radium::EnumSpec {
-            rfn_type: coq::Type::Literal(inductive_name),
+            rfn_type: coq::term::Type::Literal(inductive_name),
             variant_patterns,
         };
 
-- 
GitLab