cl-typeck: Add Handle
type
- Holds a DefID and a reference to the Project - Pretty-prints def signatures - Use handles when printing types (WIP) Known issues: - Printing recursive types recurses forever - There's some unrelated name resolution stuff going on that needs investigating. TODO: - Better name - HandleMut? - More interfaces! - Migrate everything to use handles when oop semantics are easiest - Reject plain recursive types, and don't recurse through reference types when printing
This commit is contained in:
parent
82b71e2517
commit
9d7ab77999
@ -6,6 +6,7 @@ use cl_lexer::Lexer;
|
|||||||
use cl_parser::{inliner::ModuleInliner, Parser};
|
use cl_parser::{inliner::ModuleInliner, Parser};
|
||||||
use cl_typeck::{
|
use cl_typeck::{
|
||||||
definition::Def,
|
definition::Def,
|
||||||
|
handle::Handle,
|
||||||
name_collector::NameCollector,
|
name_collector::NameCollector,
|
||||||
node::{Node, NodeSource},
|
node::{Node, NodeSource},
|
||||||
project::Project,
|
project::Project,
|
||||||
@ -118,8 +119,8 @@ fn query_type_expression(prj: &mut Project) -> Result<(), RlError> {
|
|||||||
}
|
}
|
||||||
// parse it as a path, and convert the path into a borrowed path
|
// parse it as a path, and convert the path into a borrowed path
|
||||||
let ty = Parser::new(Lexer::new(line)).ty()?.kind;
|
let ty = Parser::new(Lexer::new(line)).ty()?.kind;
|
||||||
let id = prj.evaluate(&ty, prj.root)?;
|
let id = prj.evaluate(&ty, prj.root)?.handle_unchecked(prj);
|
||||||
pretty_def(&prj[id], id);
|
pretty_handle(id)?;
|
||||||
Ok(Response::Accept)
|
Ok(Response::Accept)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -135,31 +136,43 @@ fn resolve_all(prj: &mut Project) -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
fn list_types(prj: &mut Project) {
|
fn list_types(prj: &mut Project) {
|
||||||
println!(" name\x1b[30G type");
|
println!(" name\x1b[30G type");
|
||||||
for (idx, Def { kind, node: Node { vis, kind: source, .. }, .. }) in
|
for (idx, key) in prj.pool.keys().enumerate() {
|
||||||
prj.pool.values().enumerate()
|
let Def { node: Node { vis, kind: source, .. }, .. } = &prj[key];
|
||||||
{
|
let name = match source.as_ref().map(NodeSource::name) {
|
||||||
print!("{idx:3}: {vis}");
|
Some(Some(name)) => name,
|
||||||
if let Some(Some(name)) = source.as_ref().map(NodeSource::name) {
|
_ => "".into(),
|
||||||
print!("{name}");
|
};
|
||||||
}
|
print!(
|
||||||
println!("\x1b[30G| {kind}")
|
"{idx:3}: {vis}{name}\x1b[30G = {}",
|
||||||
|
key.handle_unchecked(prj)
|
||||||
|
);
|
||||||
|
println!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pretty_def(def: &Def, id: impl Into<usize>) {
|
fn pretty_handle(handle: Handle) -> Result<(), std::io::Error> {
|
||||||
let id = id.into();
|
use std::io::Write;
|
||||||
let Def { module, kind, node: Node { meta, vis, kind: source, .. } } = def;
|
let mut stdout = std::io::stdout().lock();
|
||||||
for meta in *meta {
|
let Some(Def { module, node: Node { vis, .. }, .. }) = handle.get() else {
|
||||||
println!("#[{meta}]")
|
return writeln!(stdout, "Invalid handle: {handle}");
|
||||||
|
};
|
||||||
|
writeln!(stdout, "{C_LISTING}{vis}{handle}\x1b[0m: {}", handle.id())?;
|
||||||
|
if let Some(parent) = module.parent {
|
||||||
|
writeln!(stdout, "{C_LISTING}Parent\x1b[0m: {}", handle.with(parent))?;
|
||||||
}
|
}
|
||||||
if let Some(Some(name)) = source.as_ref().map(NodeSource::name) {
|
if !module.types.is_empty() {
|
||||||
print!("{vis}{name} ");
|
writeln!(stdout, "{C_LISTING}Types:\x1b[0m")?;
|
||||||
|
for (name, def) in &module.types {
|
||||||
|
writeln!(stdout, "- {C_LISTING}{name}\x1b[0m: {}", handle.with(*def))?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
println!("[id: {id}] = {kind}");
|
if !module.values.is_empty() {
|
||||||
if let Some(source) = source {
|
writeln!(stdout, "{C_LISTING}Values:\x1b[0m")?;
|
||||||
println!("Source:\n{C_LISTING}{source}\x1b[0m");
|
for (name, def) in &module.values {
|
||||||
|
writeln!(stdout, "- {C_LISTING}{name}\x1b[0m: {}", handle.with(*def))?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
println!("\x1b[90m{module}\x1b[0m");
|
write!(stdout, "\x1b[0m")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inline_modules(code: cl_ast::File, path: impl AsRef<path::Path>) -> cl_ast::File {
|
fn inline_modules(code: cl_ast::File, path: impl AsRef<path::Path>) -> cl_ast::File {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::{definition::Def, project::Project};
|
||||||
use cl_structures::index_map::*;
|
use cl_structures::index_map::*;
|
||||||
|
|
||||||
// define the index types
|
// define the index types
|
||||||
@ -8,8 +9,170 @@ make_index! {
|
|||||||
DefID,
|
DefID,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for DefID {
|
/// A handle to a certain [Def] within a [Project]
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
#[derive(Clone, Copy, Debug)]
|
||||||
self.0.fmt(f)
|
pub struct Handle<'prj, 'code> {
|
||||||
|
id: DefID,
|
||||||
|
prj: &'prj Project<'code>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefID {
|
||||||
|
/// Constructs a new [Handle] from this DefID and the provided [Project].
|
||||||
|
pub fn handle<'p, 'c>(self, prj: &'p Project<'c>) -> Option<Handle<'p, 'c>> {
|
||||||
|
Handle::new(self, prj)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a new [Handle] from this DefID and the provided [Project]
|
||||||
|
pub fn handle_unchecked<'p, 'c>(self, prj: &'p Project<'c>) -> Handle<'p, 'c> {
|
||||||
|
Handle::new_unchecked(self, prj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'p, 'c> Handle<'p, 'c> {
|
||||||
|
/// Constructs a new Handle from the provided [DefID] and [Project].
|
||||||
|
/// Returns [Some]\(Handle) if the [DefID] exists in the [Project].
|
||||||
|
pub fn new(id: DefID, prj: &'p Project<'c>) -> Option<Self> {
|
||||||
|
prj.pool.get(id).is_some().then_some(Self { id, prj })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a new Handle from the provided [DefID] and [Project] without checking membership.
|
||||||
|
/// Using the handle may cause panics or other unwanted (but defined) behavior.
|
||||||
|
pub fn new_unchecked(id: DefID, prj: &'p Project<'c>) -> Self {
|
||||||
|
Self { id, prj }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the [Def] this handle points to.
|
||||||
|
pub fn get(self) -> Option<&'p Def<'c>> {
|
||||||
|
self.prj.pool.get(self.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the [Project] this handle points to.
|
||||||
|
pub fn project(self) -> &'p Project<'c> {
|
||||||
|
self.prj
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(self) -> DefID {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: get parent, children, etc.
|
||||||
|
|
||||||
|
/// Gets a handle to the other ID within the same project
|
||||||
|
pub fn with(self, id: DefID) -> Self {
|
||||||
|
Self { id, ..self }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod display {
|
||||||
|
use super::*;
|
||||||
|
use crate::{definition::*, format_utils::*};
|
||||||
|
use std::fmt::{self, Display, Write};
|
||||||
|
|
||||||
|
impl Display for DefID {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Handle<'_, '_> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let Self { id, prj } = *self;
|
||||||
|
let Some(def) = prj.pool.get(id) else {
|
||||||
|
return write!(f, "<invalid type: {id}>");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Match the type
|
||||||
|
match &def.kind {
|
||||||
|
DefKind::Undecided => write!(f, "<undecided>"),
|
||||||
|
DefKind::Impl(id) => write!(f, "impl {}", self.with(*id)),
|
||||||
|
DefKind::Use(id) => write!(f, "use inside {}", self.with(*id)),
|
||||||
|
DefKind::Type(kind) => match kind {
|
||||||
|
TypeKind::Alias(None) => write!(f, "type"),
|
||||||
|
TypeKind::Alias(Some(id)) => write!(f, "{}", self.with(*id)),
|
||||||
|
TypeKind::Intrinsic(intrinsic) => write!(f, "{intrinsic}"),
|
||||||
|
TypeKind::Adt(adt) => display_adt(self, adt, f),
|
||||||
|
TypeKind::Ref(count, id) => {
|
||||||
|
for _ in 0..*count {
|
||||||
|
f.write_char('&')?;
|
||||||
|
}
|
||||||
|
self.with(*id).fmt(f)
|
||||||
|
}
|
||||||
|
TypeKind::Array(id, size) => {
|
||||||
|
write!(f.delimit_with("[", "]"), "{}; {size}", self.with(*id))
|
||||||
|
}
|
||||||
|
TypeKind::Slice(id) => write!(f.delimit_with("[", "]"), "{}", self.with(*id)),
|
||||||
|
TypeKind::Tuple(ids) => {
|
||||||
|
let mut ids = ids.iter();
|
||||||
|
separate(", ", || {
|
||||||
|
let id = ids.next()?;
|
||||||
|
Some(move |f: &mut Delimit<_>| write!(f, "{}", self.with(*id)))
|
||||||
|
})(f.delimit_with("(", ")"))
|
||||||
|
}
|
||||||
|
TypeKind::FnSig { args, rety } => {
|
||||||
|
write!(f, "fn {} -> {}", self.with(*args), self.with(*rety))
|
||||||
|
}
|
||||||
|
TypeKind::Empty => write!(f, "()"),
|
||||||
|
TypeKind::Never => write!(f, "!"),
|
||||||
|
TypeKind::Module => match def.name() {
|
||||||
|
Some(name) => write!(f, "mod {name}"),
|
||||||
|
None => write!(f, "mod"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
DefKind::Value(kind) => match kind {
|
||||||
|
ValueKind::Const(id) => write!(f, "const {}", self.with(*id)),
|
||||||
|
ValueKind::Static(id) => write!(f, "static {}", self.with(*id)),
|
||||||
|
ValueKind::Local(id) => write!(f, "local {}", self.with(*id)),
|
||||||
|
ValueKind::Fn(id) => write!(f, "{}", self.with(*id)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Formats an ADT: a continuation of [Handle::fmt]
|
||||||
|
fn display_adt(handle: &Handle, adt: &Adt, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match adt {
|
||||||
|
Adt::Enum(variants) => {
|
||||||
|
let mut variants = variants.iter();
|
||||||
|
separate(",", || {
|
||||||
|
variants.next().map(|(name, def)| {
|
||||||
|
move |f: &mut Delimit<_>| match def {
|
||||||
|
Some(def) => write!(f, "\n{name}: {}", handle.with(*def)),
|
||||||
|
None => write!(f, "\n{name}"),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})(f.delimit_with("enum {", "\n}"))
|
||||||
|
}
|
||||||
|
Adt::CLikeEnum(variants) => {
|
||||||
|
let mut variants = variants.iter();
|
||||||
|
separate(",", || {
|
||||||
|
let (name, descrim) = variants.next()?;
|
||||||
|
Some(move |f: &mut Delimit<_>| write!(f, "\n{name} = {descrim}"))
|
||||||
|
})(f.delimit_with("enum {", "\n}"))
|
||||||
|
}
|
||||||
|
Adt::FieldlessEnum => write!(f, "enum"),
|
||||||
|
Adt::Struct(members) => {
|
||||||
|
let mut members = members.iter();
|
||||||
|
separate(",", || {
|
||||||
|
let (name, vis, id) = members.next()?;
|
||||||
|
Some(move |f: &mut Delimit<_>| write!(f, "\n{vis}{name}: {}", handle.with(*id)))
|
||||||
|
})(f.delimit_with("struct {", "\n}"))
|
||||||
|
}
|
||||||
|
Adt::TupleStruct(members) => {
|
||||||
|
let mut members = members.iter();
|
||||||
|
separate(", ", || {
|
||||||
|
let (vis, def) = members.next()?;
|
||||||
|
Some(move |f: &mut Delimit<_>| write!(f, "{vis}{}", handle.with(*def)))
|
||||||
|
})(f.delimit_with("struct (", ")"))
|
||||||
|
}
|
||||||
|
Adt::UnitStruct => write!(f, "struct;"),
|
||||||
|
Adt::Union(variants) => {
|
||||||
|
let mut variants = variants.iter();
|
||||||
|
separate(",", || {
|
||||||
|
let (name, def) = variants.next()?;
|
||||||
|
Some(move |f: &mut Delimit<_>| write!(f, "\n{name}: {}", handle.with(*def)))
|
||||||
|
})(f.delimit_with("union {", "\n}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user