mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-24 13:13:43 +00:00
feat: slightly improve expression describer (#798)
* dev: simplify type union * dev: split repr crate * feat: slightly improve expression describer * dev: update snapshot * dev: change repr if there is no name
This commit is contained in:
parent
0babb8b451
commit
5616a3fb34
7 changed files with 650 additions and 358 deletions
|
@ -4,6 +4,6 @@ expression: "JsonRepr::new_redacted(result, &REDACT_LOC)"
|
|||
input_file: crates/tinymist-query/src/fixtures/hover/value_repr.typ
|
||||
---
|
||||
{
|
||||
"contents": "```typc\nlet reconstruct(\n it,\n ..new-body: arguments,\n body-name: str = \"body\",\n labeled: bool = true,\n max-depth: int = 9999,\n wrapper: () => box = Closure(..),\n) = none;\n```\n\n---\n## Parameters\n\n@positional `it`\n\n@named `body-name`\n\n@named `labeled`\n\n@named `max-depth`\n\n@named `wrapper`\n\n@rest `new-body`",
|
||||
"range": "1:20:1:31"
|
||||
"contents": "```typc\nlet f(\n x,\n y,\n z,\n w01: int = 1,\n w02: str = \"test\",\n w03: any = 1 + 2,\n w04 = Label(test),\n w05: function = box,\n w06: any = list.item,\n w07: content = Expr(..),\n w08: any = Expr(..),\n w09: any = 1 + 2,\n w10: array = (\n 1,\n 2,\n ),\n w11: array = (),\n w12: dict = (:),\n w13: dict = (a: 1),\n w14: dict = (a: box),\n w15: dict = (a: list.item),\n) = int;\n```\n\n---\n## Parameters\n\n@positional `x`\n\n@positional `y`\n\n@positional `z`\n\n@named `w01`\n\n@named `w02`\n\n@named `w03`\n\n@named `w04`\n\n@named `w05`\n\n@named `w06`\n\n@named `w07`\n\n@named `w08`\n\n@named `w09`\n\n@named `w10`\n\n@named `w11`\n\n@named `w12`\n\n@named `w13`\n\n@named `w14`\n\n@named `w15`",
|
||||
"range": "23:20:23:21"
|
||||
}
|
||||
|
|
|
@ -1,2 +1,24 @@
|
|||
#let reconstruct(body-name: "body", labeled: true, max-depth: 9999, wrapper: () => box(""), it, ..new-body) = { }
|
||||
#(/* ident after */ reconstruct);
|
||||
#let f(
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
w01: 1,
|
||||
w02: "test",
|
||||
w03: 1 + 2,
|
||||
w04: <test>,
|
||||
w05: box,
|
||||
w06: list.item,
|
||||
w07: [..],
|
||||
w08: {
|
||||
1 + 2
|
||||
},
|
||||
w09: (1 + 2),
|
||||
w10: (1, 2),
|
||||
w11: (),
|
||||
w12: (:),
|
||||
w13: (a: 1),
|
||||
w14: (a: box),
|
||||
w15: (a: list.item),
|
||||
) = 1
|
||||
|
||||
#(/* ident after */ f);
|
||||
|
|
|
@ -3,9 +3,9 @@ source: crates/tinymist-query/src/analysis.rs
|
|||
expression: result
|
||||
input_file: crates/tinymist-query/src/fixtures/type_check/bug_cite_func_infer.typ
|
||||
---
|
||||
"cite_prose" = (( ⪯ (RefLabel))) => Element(ref)
|
||||
"cite_prose" = (( ⪯ RefLabel)) => Element(ref)
|
||||
"labl" = Any
|
||||
"cite_prose_different_name" = (( ⪯ (RefLabel))) => Element(ref)
|
||||
"cite_prose_different_name" = (( ⪯ RefLabel)) => Element(ref)
|
||||
"labl" = Any
|
||||
---
|
||||
5..15 -> @cite_prose
|
||||
|
|
|
@ -16,6 +16,8 @@ use crate::{
|
|||
ty::{InsTy, Interned, SelectTy, Ty, TypeVar},
|
||||
};
|
||||
|
||||
use super::{ExprDescriber, ExprPrinter};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Expr {
|
||||
/// A sequence of expressions
|
||||
|
@ -69,10 +71,11 @@ pub enum Expr {
|
|||
/// A star import
|
||||
Star,
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
pub(crate) fn repr(&self) -> EcoString {
|
||||
let mut s = EcoString::new();
|
||||
let _ = ExprFormatter::new(&mut s, true).write_expr(self);
|
||||
let _ = ExprDescriber::new(&mut s).write_expr(self);
|
||||
s
|
||||
}
|
||||
|
||||
|
@ -95,7 +98,7 @@ impl Expr {
|
|||
|
||||
impl fmt::Display for Expr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
ExprFormatter::new(f, false).write_expr(self)
|
||||
ExprPrinter::new(f).write_expr(self)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -630,14 +633,14 @@ pub enum Pattern {
|
|||
|
||||
impl fmt::Display for Pattern {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
ExprFormatter::new(f, false).write_pattern(self)
|
||||
ExprPrinter::new(f).write_pattern(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Pattern {
|
||||
pub(crate) fn repr(&self) -> EcoString {
|
||||
let mut s = EcoString::new();
|
||||
let _ = ExprFormatter::new(&mut s, true).write_pattern(self);
|
||||
let _ = ExprDescriber::new(&mut s).write_pattern(self);
|
||||
s
|
||||
}
|
||||
}
|
||||
|
@ -902,350 +905,3 @@ impl_internable!(
|
|||
BinInst<Expr>,
|
||||
ApplyExpr,
|
||||
);
|
||||
|
||||
struct ExprFormatter<'a, T: fmt::Write> {
|
||||
f: &'a mut T,
|
||||
repr: bool,
|
||||
indent: usize,
|
||||
}
|
||||
|
||||
impl<'a, T: fmt::Write> ExprFormatter<'a, T> {
|
||||
fn new(f: &'a mut T, repr: bool) -> Self {
|
||||
Self { f, repr, indent: 0 }
|
||||
}
|
||||
|
||||
fn write_decl(&mut self, d: &Decl) -> fmt::Result {
|
||||
write!(self.f, "{d:?}")
|
||||
}
|
||||
|
||||
fn write_expr(&mut self, expr: &Expr) -> fmt::Result {
|
||||
match expr {
|
||||
Expr::Block(s) => self.write_seq(s),
|
||||
Expr::Array(a) => self.write_array(a),
|
||||
Expr::Dict(d) => self.write_dict(d),
|
||||
Expr::Args(a) => self.write_args(a),
|
||||
Expr::Pattern(p) => self.write_pattern(p),
|
||||
Expr::Element(e) => self.write_element(e),
|
||||
Expr::Unary(u) => self.write_unary(u),
|
||||
Expr::Binary(b) => self.write_binary(b),
|
||||
Expr::Apply(a) => self.write_apply(a),
|
||||
Expr::Func(func) => self.write_func(func),
|
||||
Expr::Let(l) => self.write_let(l),
|
||||
Expr::Show(s) => self.write_show(s),
|
||||
Expr::Set(s) => self.write_set(s),
|
||||
Expr::Ref(r) => self.write_ref(r),
|
||||
Expr::ContentRef(r) => self.write_content_ref(r),
|
||||
Expr::Select(s) => self.write_select(s),
|
||||
Expr::Import(i) => self.write_import(i),
|
||||
Expr::Include(i) => self.write_include(i),
|
||||
Expr::Contextual(c) => self.write_contextual(c),
|
||||
Expr::Conditional(c) => self.write_conditional(c),
|
||||
Expr::WhileLoop(w) => self.write_while_loop(w),
|
||||
Expr::ForLoop(f) => self.write_for_loop(f),
|
||||
Expr::Type(t) => self.write_type(t),
|
||||
Expr::Decl(d) => self.write_decl(d),
|
||||
Expr::Star => self.write_star(),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_indent(&mut self) -> fmt::Result {
|
||||
write!(self.f, "{:indent$}", "", indent = self.indent)
|
||||
}
|
||||
|
||||
fn write_seq(&mut self, s: &Interned<Vec<Expr>>) -> fmt::Result {
|
||||
writeln!(self.f, "[")?;
|
||||
self.indent += 1;
|
||||
for expr in s.iter() {
|
||||
self.write_indent()?;
|
||||
self.write_expr(expr)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
write!(self.f, "]")
|
||||
}
|
||||
|
||||
fn write_array(&mut self, a: &Interned<Vec<ArgExpr>>) -> fmt::Result {
|
||||
writeln!(self.f, "(")?;
|
||||
self.indent += 1;
|
||||
for arg in a.iter() {
|
||||
self.write_indent()?;
|
||||
self.write_arg(arg)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_dict(&mut self, d: &Interned<Vec<ArgExpr>>) -> fmt::Result {
|
||||
writeln!(self.f, "(:")?;
|
||||
self.indent += 1;
|
||||
for arg in d.iter() {
|
||||
self.write_indent()?;
|
||||
self.write_arg(arg)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_args(&mut self, a: &Interned<Vec<ArgExpr>>) -> fmt::Result {
|
||||
writeln!(self.f, "(")?;
|
||||
for arg in a.iter() {
|
||||
self.write_indent()?;
|
||||
self.write_arg(arg)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.write_indent()?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_arg(&mut self, a: &ArgExpr) -> fmt::Result {
|
||||
match a {
|
||||
ArgExpr::Pos(e) => self.write_expr(e),
|
||||
ArgExpr::Named(n) => {
|
||||
let n = n.as_ref();
|
||||
write!(self.f, "{n:?}: ")?;
|
||||
self.write_expr(&n.1)
|
||||
}
|
||||
ArgExpr::NamedRt(n) => {
|
||||
let n = n.as_ref();
|
||||
self.write_expr(&n.0)?;
|
||||
write!(self.f, ": ")?;
|
||||
self.write_expr(&n.1)
|
||||
}
|
||||
ArgExpr::Spread(e) => {
|
||||
write!(self.f, "..")?;
|
||||
self.write_expr(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_pattern(&mut self, p: &Pattern) -> fmt::Result {
|
||||
match p {
|
||||
Pattern::Expr(e) => self.write_expr(e),
|
||||
Pattern::Simple(s) => self.write_decl(s),
|
||||
Pattern::Sig(p) => self.write_pattern_sig(p),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_pattern_sig(&mut self, p: &PatternSig) -> fmt::Result {
|
||||
self.f.write_str("pat(\n")?;
|
||||
self.indent += 1;
|
||||
for pos in &p.pos {
|
||||
self.write_indent()?;
|
||||
self.write_pattern(pos)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
for (name, pat) in &p.named {
|
||||
self.write_indent()?;
|
||||
write!(self.f, "{name:?} = ")?;
|
||||
self.write_pattern(pat)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
if let Some((k, rest)) = &p.spread_left {
|
||||
self.write_indent()?;
|
||||
write!(self.f, "..{k:?}: ")?;
|
||||
self.write_pattern(rest)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
if let Some((k, rest)) = &p.spread_right {
|
||||
self.write_indent()?;
|
||||
write!(self.f, "..{k:?}: ")?;
|
||||
self.write_pattern(rest)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_element(&mut self, e: &Interned<ElementExpr>) -> fmt::Result {
|
||||
self.f.write_str("elem(\n")?;
|
||||
self.indent += 1;
|
||||
for v in &e.content {
|
||||
self.write_indent()?;
|
||||
self.write_expr(v)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_unary(&mut self, u: &Interned<UnExpr>) -> fmt::Result {
|
||||
write!(self.f, "un({:?})(", u.op)?;
|
||||
self.write_expr(&u.lhs)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_binary(&mut self, b: &Interned<BinExpr>) -> fmt::Result {
|
||||
let [lhs, rhs] = b.operands();
|
||||
write!(self.f, "bin({:?})(", b.op)?;
|
||||
self.write_expr(lhs)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(rhs)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_apply(&mut self, a: &Interned<ApplyExpr>) -> fmt::Result {
|
||||
write!(self.f, "apply(")?;
|
||||
self.write_expr(&a.callee)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(&a.args)?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_func(&mut self, func: &Interned<FuncExpr>) -> fmt::Result {
|
||||
if self.repr {
|
||||
return self.write_decl(&func.decl);
|
||||
}
|
||||
|
||||
write!(self.f, "func[{:?}](", func.decl)?;
|
||||
self.write_pattern_sig(&func.params)?;
|
||||
write!(self.f, " = ")?;
|
||||
self.write_expr(&func.body)?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_let(&mut self, l: &Interned<LetExpr>) -> fmt::Result {
|
||||
write!(self.f, "let(")?;
|
||||
self.write_pattern(&l.pattern)?;
|
||||
if let Some(body) = &l.body {
|
||||
write!(self.f, " = ")?;
|
||||
self.write_expr(body)?;
|
||||
}
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_show(&mut self, s: &Interned<ShowExpr>) -> fmt::Result {
|
||||
write!(self.f, "show(")?;
|
||||
if let Some(selector) = &s.selector {
|
||||
self.write_expr(selector)?;
|
||||
self.f.write_str(", ")?;
|
||||
}
|
||||
self.write_expr(&s.edit)?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_set(&mut self, s: &Interned<SetExpr>) -> fmt::Result {
|
||||
write!(self.f, "set(")?;
|
||||
self.write_expr(&s.target)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(&s.args)?;
|
||||
if let Some(cond) = &s.cond {
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(cond)?;
|
||||
}
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_ref(&mut self, r: &Interned<RefExpr>) -> fmt::Result {
|
||||
write!(self.f, "ref({:?}", r.decl)?;
|
||||
if let Some(step) = &r.step {
|
||||
self.f.write_str(", step = ")?;
|
||||
self.write_expr(step)?;
|
||||
}
|
||||
if let Some(of) = &r.root {
|
||||
self.f.write_str(", root = ")?;
|
||||
self.write_expr(of)?;
|
||||
}
|
||||
if let Some(val) = &r.val {
|
||||
write!(self.f, ", val = {val:?}")?;
|
||||
}
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_content_ref(&mut self, r: &Interned<ContentRefExpr>) -> fmt::Result {
|
||||
write!(self.f, "content_ref({:?}", r.ident)?;
|
||||
if let Some(of) = &r.of {
|
||||
self.f.write_str(", ")?;
|
||||
self.write_decl(of)?;
|
||||
}
|
||||
if let Some(val) = &r.body {
|
||||
self.write_expr(val)?;
|
||||
}
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_select(&mut self, s: &Interned<SelectExpr>) -> fmt::Result {
|
||||
write!(self.f, "(")?;
|
||||
self.write_expr(&s.lhs)?;
|
||||
self.f.write_str(").")?;
|
||||
self.write_decl(&s.key)
|
||||
}
|
||||
|
||||
fn write_import(&mut self, i: &Interned<ImportExpr>) -> fmt::Result {
|
||||
self.f.write_str("import(")?;
|
||||
self.write_decl(&i.decl)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_include(&mut self, i: &Interned<IncludeExpr>) -> fmt::Result {
|
||||
self.f.write_str("include(")?;
|
||||
self.write_expr(&i.source)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_contextual(&mut self, c: &Interned<Expr>) -> fmt::Result {
|
||||
if self.repr {
|
||||
return self.f.write_str("content");
|
||||
}
|
||||
|
||||
self.f.write_str("contextual(")?;
|
||||
self.write_expr(c)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_conditional(&mut self, c: &Interned<IfExpr>) -> fmt::Result {
|
||||
if self.repr {
|
||||
return self.f.write_str("Expr(..)");
|
||||
}
|
||||
|
||||
self.f.write_str("if(")?;
|
||||
self.write_expr(&c.cond)?;
|
||||
self.f.write_str(", then = ")?;
|
||||
self.write_expr(&c.then)?;
|
||||
self.f.write_str(", else = ")?;
|
||||
self.write_expr(&c.else_)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_while_loop(&mut self, w: &Interned<WhileExpr>) -> fmt::Result {
|
||||
if self.repr {
|
||||
return self.f.write_str("Expr(..)");
|
||||
}
|
||||
|
||||
self.f.write_str("while(")?;
|
||||
self.write_expr(&w.cond)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(&w.body)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_for_loop(&mut self, f: &Interned<ForExpr>) -> fmt::Result {
|
||||
if self.repr {
|
||||
return self.f.write_str("Expr(..)");
|
||||
}
|
||||
|
||||
self.f.write_str("for(")?;
|
||||
self.write_pattern(&f.pattern)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(&f.iter)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(&f.body)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_type(&mut self, t: &Ty) -> fmt::Result {
|
||||
let formatted = t.describe();
|
||||
let formatted = formatted.as_deref().unwrap_or("any");
|
||||
self.f.write_str(formatted)
|
||||
}
|
||||
|
||||
fn write_star(&mut self) -> fmt::Result {
|
||||
self.f.write_str("*")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,3 +20,5 @@ pub(crate) mod docs;
|
|||
pub use docs::*;
|
||||
pub(crate) mod def;
|
||||
pub use def::*;
|
||||
pub(crate) mod repr;
|
||||
use repr::*;
|
||||
|
|
607
crates/tinymist-query/src/syntax/repr.rs
Normal file
607
crates/tinymist-query/src/syntax/repr.rs
Normal file
|
@ -0,0 +1,607 @@
|
|||
use core::fmt;
|
||||
|
||||
use super::def::*;
|
||||
use crate::ty::{Interned, Ty};
|
||||
|
||||
pub(in crate::syntax) struct ExprPrinter<'a, T: fmt::Write> {
|
||||
f: &'a mut T,
|
||||
indent: usize,
|
||||
}
|
||||
|
||||
impl<'a, T: fmt::Write> ExprPrinter<'a, T> {
|
||||
pub fn new(f: &'a mut T) -> Self {
|
||||
Self { f, indent: 0 }
|
||||
}
|
||||
|
||||
pub fn write_decl(&mut self, d: &Decl) -> fmt::Result {
|
||||
write!(self.f, "{d:?}")
|
||||
}
|
||||
|
||||
pub fn write_expr(&mut self, expr: &Expr) -> fmt::Result {
|
||||
match expr {
|
||||
Expr::Block(s) => self.write_seq(s),
|
||||
Expr::Array(a) => self.write_array(a),
|
||||
Expr::Dict(d) => self.write_dict(d),
|
||||
Expr::Args(a) => self.write_args(a),
|
||||
Expr::Pattern(p) => self.write_pattern(p),
|
||||
Expr::Element(e) => self.write_element(e),
|
||||
Expr::Unary(u) => self.write_unary(u),
|
||||
Expr::Binary(b) => self.write_binary(b),
|
||||
Expr::Apply(a) => self.write_apply(a),
|
||||
Expr::Func(func) => self.write_func(func),
|
||||
Expr::Let(l) => self.write_let(l),
|
||||
Expr::Show(s) => self.write_show(s),
|
||||
Expr::Set(s) => self.write_set(s),
|
||||
Expr::Ref(r) => self.write_ref(r),
|
||||
Expr::ContentRef(r) => self.write_content_ref(r),
|
||||
Expr::Select(s) => self.write_select(s),
|
||||
Expr::Import(i) => self.write_import(i),
|
||||
Expr::Include(i) => self.write_include(i),
|
||||
Expr::Contextual(c) => self.write_contextual(c),
|
||||
Expr::Conditional(c) => self.write_conditional(c),
|
||||
Expr::WhileLoop(w) => self.write_while_loop(w),
|
||||
Expr::ForLoop(f) => self.write_for_loop(f),
|
||||
Expr::Type(t) => self.write_type(t),
|
||||
Expr::Decl(d) => self.write_decl(d),
|
||||
Expr::Star => self.write_star(),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_indent(&mut self) -> fmt::Result {
|
||||
write!(self.f, "{:indent$}", "", indent = self.indent)
|
||||
}
|
||||
|
||||
fn write_seq(&mut self, s: &Interned<Vec<Expr>>) -> fmt::Result {
|
||||
writeln!(self.f, "[")?;
|
||||
self.indent += 1;
|
||||
for expr in s.iter() {
|
||||
self.write_indent()?;
|
||||
self.write_expr(expr)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
write!(self.f, "]")
|
||||
}
|
||||
|
||||
fn write_array(&mut self, a: &Interned<Vec<ArgExpr>>) -> fmt::Result {
|
||||
writeln!(self.f, "(")?;
|
||||
self.indent += 1;
|
||||
for arg in a.iter() {
|
||||
self.write_indent()?;
|
||||
self.write_arg(arg)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_dict(&mut self, d: &Interned<Vec<ArgExpr>>) -> fmt::Result {
|
||||
writeln!(self.f, "(:")?;
|
||||
self.indent += 1;
|
||||
for arg in d.iter() {
|
||||
self.write_indent()?;
|
||||
self.write_arg(arg)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_args(&mut self, a: &Interned<Vec<ArgExpr>>) -> fmt::Result {
|
||||
writeln!(self.f, "(")?;
|
||||
for arg in a.iter() {
|
||||
self.write_indent()?;
|
||||
self.write_arg(arg)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.write_indent()?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_arg(&mut self, a: &ArgExpr) -> fmt::Result {
|
||||
match a {
|
||||
ArgExpr::Pos(e) => self.write_expr(e),
|
||||
ArgExpr::Named(n) => {
|
||||
let (k, v) = n.as_ref();
|
||||
write!(self.f, "{k:?}: ")?;
|
||||
self.write_expr(v)
|
||||
}
|
||||
ArgExpr::NamedRt(n) => {
|
||||
let n = n.as_ref();
|
||||
self.write_expr(&n.0)?;
|
||||
write!(self.f, ": ")?;
|
||||
self.write_expr(&n.1)
|
||||
}
|
||||
ArgExpr::Spread(e) => {
|
||||
write!(self.f, "..")?;
|
||||
self.write_expr(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_pattern(&mut self, p: &Pattern) -> fmt::Result {
|
||||
match p {
|
||||
Pattern::Expr(e) => self.write_expr(e),
|
||||
Pattern::Simple(s) => self.write_decl(s),
|
||||
Pattern::Sig(p) => self.write_pattern_sig(p),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_pattern_sig(&mut self, p: &PatternSig) -> fmt::Result {
|
||||
self.f.write_str("pat(\n")?;
|
||||
self.indent += 1;
|
||||
for pos in &p.pos {
|
||||
self.write_indent()?;
|
||||
self.write_pattern(pos)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
for (name, pat) in &p.named {
|
||||
self.write_indent()?;
|
||||
write!(self.f, "{name:?} = ")?;
|
||||
self.write_pattern(pat)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
if let Some((k, rest)) = &p.spread_left {
|
||||
self.write_indent()?;
|
||||
write!(self.f, "..{k:?}: ")?;
|
||||
self.write_pattern(rest)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
if let Some((k, rest)) = &p.spread_right {
|
||||
self.write_indent()?;
|
||||
write!(self.f, "..{k:?}: ")?;
|
||||
self.write_pattern(rest)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_element(&mut self, e: &Interned<ElementExpr>) -> fmt::Result {
|
||||
self.f.write_str("elem(\n")?;
|
||||
self.indent += 1;
|
||||
for v in &e.content {
|
||||
self.write_indent()?;
|
||||
self.write_expr(v)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_unary(&mut self, u: &Interned<UnExpr>) -> fmt::Result {
|
||||
write!(self.f, "un({:?})(", u.op)?;
|
||||
self.write_expr(&u.lhs)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_binary(&mut self, b: &Interned<BinExpr>) -> fmt::Result {
|
||||
let [lhs, rhs] = b.operands();
|
||||
write!(self.f, "bin({:?})(", b.op)?;
|
||||
self.write_expr(lhs)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(rhs)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_apply(&mut self, a: &Interned<ApplyExpr>) -> fmt::Result {
|
||||
write!(self.f, "apply(")?;
|
||||
self.write_expr(&a.callee)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(&a.args)?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_func(&mut self, func: &Interned<FuncExpr>) -> fmt::Result {
|
||||
write!(self.f, "func[{:?}](", func.decl)?;
|
||||
self.write_pattern_sig(&func.params)?;
|
||||
write!(self.f, " = ")?;
|
||||
self.write_expr(&func.body)?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_let(&mut self, l: &Interned<LetExpr>) -> fmt::Result {
|
||||
write!(self.f, "let(")?;
|
||||
self.write_pattern(&l.pattern)?;
|
||||
if let Some(body) = &l.body {
|
||||
write!(self.f, " = ")?;
|
||||
self.write_expr(body)?;
|
||||
}
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_show(&mut self, s: &Interned<ShowExpr>) -> fmt::Result {
|
||||
write!(self.f, "show(")?;
|
||||
if let Some(selector) = &s.selector {
|
||||
self.write_expr(selector)?;
|
||||
self.f.write_str(", ")?;
|
||||
}
|
||||
self.write_expr(&s.edit)?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_set(&mut self, s: &Interned<SetExpr>) -> fmt::Result {
|
||||
write!(self.f, "set(")?;
|
||||
self.write_expr(&s.target)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(&s.args)?;
|
||||
if let Some(cond) = &s.cond {
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(cond)?;
|
||||
}
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_ref(&mut self, r: &Interned<RefExpr>) -> fmt::Result {
|
||||
write!(self.f, "ref({:?}", r.decl)?;
|
||||
if let Some(step) = &r.step {
|
||||
self.f.write_str(", step = ")?;
|
||||
self.write_expr(step)?;
|
||||
}
|
||||
if let Some(of) = &r.root {
|
||||
self.f.write_str(", root = ")?;
|
||||
self.write_expr(of)?;
|
||||
}
|
||||
if let Some(val) = &r.val {
|
||||
write!(self.f, ", val = {val:?}")?;
|
||||
}
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_content_ref(&mut self, r: &Interned<ContentRefExpr>) -> fmt::Result {
|
||||
write!(self.f, "content_ref({:?}", r.ident)?;
|
||||
if let Some(of) = &r.of {
|
||||
self.f.write_str(", ")?;
|
||||
self.write_decl(of)?;
|
||||
}
|
||||
if let Some(val) = &r.body {
|
||||
self.write_expr(val)?;
|
||||
}
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_select(&mut self, s: &Interned<SelectExpr>) -> fmt::Result {
|
||||
write!(self.f, "(")?;
|
||||
self.write_expr(&s.lhs)?;
|
||||
self.f.write_str(").")?;
|
||||
self.write_decl(&s.key)
|
||||
}
|
||||
|
||||
fn write_import(&mut self, i: &Interned<ImportExpr>) -> fmt::Result {
|
||||
self.f.write_str("import(")?;
|
||||
self.write_decl(&i.decl)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_include(&mut self, i: &Interned<IncludeExpr>) -> fmt::Result {
|
||||
self.f.write_str("include(")?;
|
||||
self.write_expr(&i.source)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_contextual(&mut self, c: &Interned<Expr>) -> fmt::Result {
|
||||
self.f.write_str("contextual(")?;
|
||||
self.write_expr(c)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_conditional(&mut self, c: &Interned<IfExpr>) -> fmt::Result {
|
||||
self.f.write_str("if(")?;
|
||||
self.write_expr(&c.cond)?;
|
||||
self.f.write_str(", then = ")?;
|
||||
self.write_expr(&c.then)?;
|
||||
self.f.write_str(", else = ")?;
|
||||
self.write_expr(&c.else_)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_while_loop(&mut self, w: &Interned<WhileExpr>) -> fmt::Result {
|
||||
self.f.write_str("while(")?;
|
||||
self.write_expr(&w.cond)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(&w.body)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_for_loop(&mut self, f: &Interned<ForExpr>) -> fmt::Result {
|
||||
self.f.write_str("for(")?;
|
||||
self.write_pattern(&f.pattern)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(&f.iter)?;
|
||||
self.f.write_str(", ")?;
|
||||
self.write_expr(&f.body)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_type(&mut self, t: &Ty) -> fmt::Result {
|
||||
let formatted = t.describe();
|
||||
let formatted = formatted.as_deref().unwrap_or("any");
|
||||
self.f.write_str(formatted)
|
||||
}
|
||||
|
||||
fn write_star(&mut self) -> fmt::Result {
|
||||
self.f.write_str("*")
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::syntax) struct ExprDescriber<'a, T: fmt::Write> {
|
||||
f: &'a mut T,
|
||||
indent: usize,
|
||||
}
|
||||
|
||||
impl<'a, T: fmt::Write> ExprDescriber<'a, T> {
|
||||
pub fn new(f: &'a mut T) -> Self {
|
||||
Self { f, indent: 0 }
|
||||
}
|
||||
|
||||
pub fn write_decl(&mut self, d: &Decl) -> fmt::Result {
|
||||
use DefKind::*;
|
||||
let shorter = matches!(d.kind(), Function | Variable | Module);
|
||||
if shorter && !d.name().is_empty() {
|
||||
return write!(self.f, "{}", d.name());
|
||||
}
|
||||
|
||||
write!(self.f, "{d:?}")
|
||||
}
|
||||
|
||||
pub fn write_expr(&mut self, expr: &Expr) -> fmt::Result {
|
||||
match expr {
|
||||
Expr::Block(..) => self.f.write_str("Expr(..)"),
|
||||
Expr::Array(a) => self.write_array(a),
|
||||
Expr::Dict(d) => self.write_dict(d),
|
||||
Expr::Args(a) => self.write_args(a),
|
||||
Expr::Pattern(p) => self.write_pattern(p),
|
||||
Expr::Element(e) => self.write_element(e),
|
||||
Expr::Unary(u) => self.write_unary(u),
|
||||
Expr::Binary(b) => self.write_binary(b),
|
||||
Expr::Apply(a) => self.write_apply(a),
|
||||
Expr::Func(func) => self.write_func(func),
|
||||
Expr::Ref(r) => self.write_ref(r),
|
||||
Expr::ContentRef(r) => self.write_content_ref(r),
|
||||
Expr::Select(s) => self.write_select(s),
|
||||
Expr::Import(i) => self.write_import(i),
|
||||
Expr::Include(i) => self.write_include(i),
|
||||
Expr::Contextual(..) => self.f.write_str("content"),
|
||||
Expr::Let(..) | Expr::Show(..) | Expr::Set(..) => self.f.write_str("Expr(..)"),
|
||||
Expr::Conditional(..) | Expr::WhileLoop(..) | Expr::ForLoop(..) => {
|
||||
self.f.write_str("Expr(..)")
|
||||
}
|
||||
Expr::Type(t) => self.write_type(t),
|
||||
Expr::Decl(d) => self.write_decl(d),
|
||||
Expr::Star => self.f.write_str("*"),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_indent(&mut self) -> fmt::Result {
|
||||
write!(self.f, "{:indent$}", "", indent = self.indent)
|
||||
}
|
||||
|
||||
fn write_array(&mut self, a: &Interned<Vec<ArgExpr>>) -> fmt::Result {
|
||||
if a.len() <= 1 {
|
||||
self.f.write_char('(')?;
|
||||
if let Some(arg) = a.first() {
|
||||
self.write_arg(arg)?;
|
||||
self.f.write_str(",")?
|
||||
}
|
||||
return self.f.write_str(")");
|
||||
}
|
||||
|
||||
writeln!(self.f, "(")?;
|
||||
self.indent += 1;
|
||||
for arg in a.iter() {
|
||||
self.write_indent()?;
|
||||
self.write_arg(arg)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_dict(&mut self, d: &Interned<Vec<ArgExpr>>) -> fmt::Result {
|
||||
if d.len() <= 1 {
|
||||
self.f.write_char('(')?;
|
||||
if let Some(arg) = d.first() {
|
||||
self.write_arg(arg)?;
|
||||
} else {
|
||||
self.f.write_str(":")?
|
||||
}
|
||||
return self.f.write_str(")");
|
||||
}
|
||||
|
||||
writeln!(self.f, "(:")?;
|
||||
self.indent += 1;
|
||||
for arg in d.iter() {
|
||||
self.write_indent()?;
|
||||
self.write_arg(arg)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_args(&mut self, a: &Interned<Vec<ArgExpr>>) -> fmt::Result {
|
||||
writeln!(self.f, "(")?;
|
||||
for arg in a.iter() {
|
||||
self.write_indent()?;
|
||||
self.write_arg(arg)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.write_indent()?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_arg(&mut self, a: &ArgExpr) -> fmt::Result {
|
||||
match a {
|
||||
ArgExpr::Pos(e) => self.write_expr(e),
|
||||
ArgExpr::Named(n) => {
|
||||
let (k, v) = n.as_ref();
|
||||
self.write_decl(k)?;
|
||||
write!(self.f, ": ")?;
|
||||
self.write_expr(v)
|
||||
}
|
||||
ArgExpr::NamedRt(n) => {
|
||||
let n = n.as_ref();
|
||||
self.write_expr(&n.0)?;
|
||||
write!(self.f, ": ")?;
|
||||
self.write_expr(&n.1)
|
||||
}
|
||||
ArgExpr::Spread(e) => {
|
||||
write!(self.f, "..")?;
|
||||
self.write_expr(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_pattern(&mut self, p: &Pattern) -> fmt::Result {
|
||||
match p {
|
||||
Pattern::Expr(e) => self.write_expr(e),
|
||||
Pattern::Simple(s) => self.write_decl(s),
|
||||
Pattern::Sig(p) => self.write_pattern_sig(p),
|
||||
}
|
||||
}
|
||||
|
||||
fn write_pattern_sig(&mut self, p: &PatternSig) -> fmt::Result {
|
||||
self.f.write_str("pat(\n")?;
|
||||
self.indent += 1;
|
||||
for pos in &p.pos {
|
||||
self.write_indent()?;
|
||||
self.write_pattern(pos)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
for (name, pat) in &p.named {
|
||||
self.write_indent()?;
|
||||
write!(self.f, "{name:?} = ")?;
|
||||
self.write_pattern(pat)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
if let Some((k, rest)) = &p.spread_left {
|
||||
self.write_indent()?;
|
||||
write!(self.f, "..{k:?}: ")?;
|
||||
self.write_pattern(rest)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
if let Some((k, rest)) = &p.spread_right {
|
||||
self.write_indent()?;
|
||||
write!(self.f, "..{k:?}: ")?;
|
||||
self.write_pattern(rest)?;
|
||||
self.f.write_str(",\n")?;
|
||||
}
|
||||
self.indent -= 1;
|
||||
self.write_indent()?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_element(&mut self, e: &Interned<ElementExpr>) -> fmt::Result {
|
||||
write!(self.f, "{:?}", e.elem.name())
|
||||
}
|
||||
|
||||
fn write_unary(&mut self, u: &Interned<UnExpr>) -> fmt::Result {
|
||||
use UnaryOp::*;
|
||||
match u.op {
|
||||
Pos => {
|
||||
self.f.write_str("+")?;
|
||||
self.write_expr(&u.lhs)
|
||||
}
|
||||
Neg => {
|
||||
self.f.write_str("-")?;
|
||||
self.write_expr(&u.lhs)
|
||||
}
|
||||
Not => {
|
||||
self.f.write_str("not ")?;
|
||||
self.write_expr(&u.lhs)
|
||||
}
|
||||
Return => {
|
||||
self.f.write_str("return ")?;
|
||||
self.write_expr(&u.lhs)
|
||||
}
|
||||
Context => {
|
||||
self.f.write_str("context ")?;
|
||||
self.write_expr(&u.lhs)
|
||||
}
|
||||
Spread => {
|
||||
self.f.write_str("..")?;
|
||||
self.write_expr(&u.lhs)
|
||||
}
|
||||
NotElementOf => {
|
||||
self.f.write_str("not elementOf(")?;
|
||||
self.write_expr(&u.lhs)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
ElementOf => {
|
||||
self.f.write_str("elementOf(")?;
|
||||
self.write_expr(&u.lhs)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
TypeOf => {
|
||||
self.f.write_str("typeOf(")?;
|
||||
self.write_expr(&u.lhs)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_binary(&mut self, b: &Interned<BinExpr>) -> fmt::Result {
|
||||
let [lhs, rhs] = b.operands();
|
||||
self.write_expr(lhs)?;
|
||||
write!(self.f, " {} ", b.op.as_str())?;
|
||||
self.write_expr(rhs)
|
||||
}
|
||||
|
||||
fn write_apply(&mut self, a: &Interned<ApplyExpr>) -> fmt::Result {
|
||||
self.write_expr(&a.callee)?;
|
||||
write!(self.f, "(")?;
|
||||
self.write_expr(&a.args)?;
|
||||
write!(self.f, ")")
|
||||
}
|
||||
|
||||
fn write_func(&mut self, func: &Interned<FuncExpr>) -> fmt::Result {
|
||||
self.write_decl(&func.decl)
|
||||
}
|
||||
|
||||
fn write_ref(&mut self, r: &Interned<RefExpr>) -> fmt::Result {
|
||||
if let Some(r) = &r.root {
|
||||
return self.write_expr(r);
|
||||
}
|
||||
if let Some(r) = &r.val {
|
||||
return self.write_type(r);
|
||||
}
|
||||
|
||||
write!(self.f, "undefined({:?})", r.decl)
|
||||
}
|
||||
|
||||
fn write_content_ref(&mut self, r: &Interned<ContentRefExpr>) -> fmt::Result {
|
||||
write!(self.f, "@{:?}", r.ident)
|
||||
}
|
||||
|
||||
fn write_select(&mut self, s: &Interned<SelectExpr>) -> fmt::Result {
|
||||
write!(self.f, "")?;
|
||||
self.write_expr(&s.lhs)?;
|
||||
self.f.write_str(".")?;
|
||||
self.write_decl(&s.key)
|
||||
}
|
||||
|
||||
fn write_import(&mut self, i: &Interned<ImportExpr>) -> fmt::Result {
|
||||
self.f.write_str("import(")?;
|
||||
self.write_decl(&i.decl)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_include(&mut self, i: &Interned<IncludeExpr>) -> fmt::Result {
|
||||
self.f.write_str("include(")?;
|
||||
self.write_expr(&i.source)?;
|
||||
self.f.write_str(")")
|
||||
}
|
||||
|
||||
fn write_type(&mut self, t: &Ty) -> fmt::Result {
|
||||
let formatted = t.describe();
|
||||
let formatted = formatted.as_deref().unwrap_or("any");
|
||||
self.f.write_str(formatted)
|
||||
}
|
||||
}
|
|
@ -219,7 +219,12 @@ impl<'a, 'b> TypeSimplifier<'a, 'b> {
|
|||
self.transform(&i.then, pol).into(),
|
||||
self.transform(&i.else_, pol).into(),
|
||||
)),
|
||||
Ty::Union(v) => Ty::Union(self.transform_seq(v, pol)),
|
||||
Ty::Union(seq) => {
|
||||
let seq = seq.iter().map(|ty| self.transform(ty, pol));
|
||||
let seq_no_any = seq.filter(|ty| !matches!(ty, Ty::Any));
|
||||
let seq = seq_no_any.collect::<Vec<_>>();
|
||||
Ty::from_types(seq.into_iter())
|
||||
}
|
||||
Ty::Field(ty) => {
|
||||
let mut ty = ty.as_ref().clone();
|
||||
ty.field = self.transform(&ty.field, pol);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue