Skip to main content

prqlc/ir/
decl.rs

1use std::collections::HashMap;
2use std::fmt::Debug;
3
4use enum_as_inner::EnumAsInner;
5use itertools::Itertools;
6use serde::{Deserialize, Serialize};
7
8use crate::codegen::write_ty;
9use crate::ir::pl;
10use crate::pr::{Span, Ty};
11use crate::semantic::write_pl;
12
13/// Context of the pipeline.
14#[derive(Default, Serialize, Deserialize, Clone)]
15pub struct RootModule {
16    /// Map of all accessible names (for each namespace)
17    pub module: Module,
18
19    pub span_map: HashMap<usize, Span>,
20}
21
22#[derive(Default, PartialEq, Serialize, Deserialize, Clone)]
23pub struct Module {
24    /// Names declared in this module. This is the important thing.
25    pub names: HashMap<String, Decl>,
26
27    /// List of relative paths to include in search path when doing lookup in
28    /// this module.
29    ///
30    /// Assuming we want to lookup `average`, which is in `std`. The root module
31    /// does not contain the `average`. So instead:
32    /// - look for `average` in root module and find nothing,
33    /// - follow redirects in root module,
34    /// - because of redirect `std`, so we look for `average` in `std`,
35    /// - there is `average` is `std`,
36    /// - result of the lookup is FQ ident `std.average`.
37    pub redirects: Vec<pl::Ident>,
38
39    /// A declaration that has been shadowed (overwritten) by this module.
40    pub shadowed: Option<Box<Decl>>,
41}
42
43/// A struct containing information about a single declaration.
44#[derive(Debug, PartialEq, Default, Serialize, Deserialize, Clone)]
45pub struct Decl {
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub declared_at: Option<usize>,
48
49    pub kind: DeclKind,
50
51    /// Some declarations (like relation columns) have an order to them.
52    /// 0 means that the order is irrelevant.
53    #[serde(skip_serializing_if = "is_zero")]
54    pub order: usize,
55
56    #[serde(skip_serializing_if = "Vec::is_empty")]
57    pub annotations: Vec<pl::Annotation>,
58}
59
60/// The Declaration itself.
61#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, EnumAsInner)]
62pub enum DeclKind {
63    /// A nested namespace
64    Module(Module),
65
66    /// Nested namespaces that do lookup in layers from top to bottom, stopping at first match.
67    LayeredModules(Vec<Module>),
68
69    TableDecl(TableDecl),
70
71    InstanceOf(pl::Ident, Option<Ty>),
72
73    /// A single column. Contains id of target which is either:
74    /// - an input relation that is source of this column or
75    /// - a column expression.
76    Column(usize),
77
78    /// Contains a default value to be created in parent namespace when NS_INFER is matched.
79    Infer(Box<DeclKind>),
80
81    Expr(Box<pl::Expr>),
82
83    Ty(Ty),
84
85    QueryDef(pl::QueryDef),
86
87    /// Equivalent to the declaration pointed to by the fully qualified ident
88    Import(pl::Ident),
89}
90
91#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
92pub struct TableDecl {
93    /// This will always be `TyKind::Array(TyKind::Tuple)`.
94    /// It is being preparing to be merged with [DeclKind::Expr].
95    /// It used to keep track of columns.
96    pub ty: Option<Ty>,
97
98    pub expr: TableExpr,
99}
100
101#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, EnumAsInner)]
102pub enum TableExpr {
103    /// In SQL, this is a CTE
104    RelationVar(Box<pl::Expr>),
105
106    /// Actual table in a database. In SQL it can be referred to by name.
107    LocalTable,
108
109    /// No expression (this decl just tracks a relation literal).
110    None,
111
112    /// A placeholder for a relation that will be provided later.
113    Param(String),
114}
115
116#[derive(Clone, Eq, Debug, PartialEq, Serialize, Deserialize)]
117pub enum TableColumn {
118    Wildcard,
119    Single(Option<String>),
120}
121
122impl std::fmt::Debug for RootModule {
123    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124        self.module.fmt(f)
125    }
126}
127
128impl std::fmt::Debug for Module {
129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130        let mut ds = f.debug_struct("Module");
131
132        if !self.redirects.is_empty() {
133            let redirects = self.redirects.iter().map(|x| x.to_string()).collect_vec();
134            ds.field("redirects", &redirects);
135        }
136
137        if self.names.len() < 15 {
138            ds.field("names", &DebugNames(&self.names));
139        } else {
140            ds.field("names", &format!("... {} entries ...", self.names.len()));
141        }
142        if self.shadowed.is_some() {
143            ds.field("shadowed", &"(hidden)");
144        }
145        ds.finish()
146    }
147}
148
149struct DebugNames<'a>(&'a HashMap<String, Decl>);
150
151impl std::fmt::Debug for DebugNames<'_> {
152    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153        let mut dm = f.debug_map();
154        for (n, decl) in self.0.iter().sorted_by_key(|x| x.0) {
155            dm.entry(n, decl);
156        }
157        dm.finish()
158    }
159}
160
161impl Default for DeclKind {
162    fn default() -> Self {
163        DeclKind::Module(Module::default())
164    }
165}
166
167impl From<DeclKind> for Decl {
168    fn from(kind: DeclKind) -> Self {
169        Decl {
170            kind,
171            declared_at: None,
172            order: 0,
173            annotations: Vec::new(),
174        }
175    }
176}
177
178impl std::fmt::Display for Decl {
179    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180        std::fmt::Display::fmt(&self.kind, f)
181    }
182}
183
184impl std::fmt::Display for DeclKind {
185    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186        match self {
187            Self::Module(arg0) => f.debug_tuple("Module").field(arg0).finish(),
188            Self::LayeredModules(arg0) => f.debug_tuple("LayeredModules").field(arg0).finish(),
189            Self::TableDecl(TableDecl { ty, expr }) => {
190                write!(
191                    f,
192                    "TableDecl: {} {expr:?}",
193                    ty.as_ref().map(write_ty).unwrap_or_default()
194                )
195            }
196            Self::InstanceOf(arg0, _) => write!(f, "InstanceOf: {arg0}"),
197            Self::Column(arg0) => write!(f, "Column (target {arg0})"),
198            Self::Infer(arg0) => write!(f, "Infer (default: {arg0})"),
199            Self::Expr(arg0) => write!(f, "Expr: {}", write_pl(*arg0.clone())),
200            Self::Ty(arg0) => write!(f, "Ty: {}", write_ty(arg0)),
201            Self::QueryDef(_) => write!(f, "QueryDef"),
202            Self::Import(arg0) => write!(f, "Import {arg0}"),
203        }
204    }
205}
206
207fn is_zero(x: &usize) -> bool {
208    *x == 0
209}