1use std::rc::Rc;
3use syn::{Ident, LitStr, Result};
4
5use crate::{
6 ast::StmtTempl,
7 data::Template,
8 metadata::Metadata,
9 syntax::{BlockTempl, LayoutTempl},
10};
11
12mod visitor;
13mod validate;
14
15use visitor::SynVisitor;
16use validate::ValidateVisitor;
17
18pub struct File {
20 layout: Option<LayoutTempl>,
21 imports: Vec<Import>,
22 blocks: Vec<BlockContent>,
23 statics: Vec<Rc<str>>,
24 stmts: Vec<StmtTempl>,
25}
26
27pub struct BlockContent {
28 pub templ: BlockTempl,
29 pub stmts: Vec<StmtTempl>,
30}
31
32impl File {
33 pub fn from_meta(meta: &Metadata) -> Result<File> {
35 let file = SynVisitor::generate(meta)?;
36 ValidateVisitor::validate(&file)?;
37 Ok(file)
38 }
39
40 pub fn get_block(&self, block: &Ident) -> Option<&BlockContent> {
42 self.blocks.iter().find(|e| &e.templ.name == block)
43 }
44
45 pub(crate) fn block(&self, block: &Ident) -> &BlockContent {
46 self.get_block(block).expect("[BUG] validation block rendering missed")
47 }
48
49 pub fn get_import_by_id(&self, name: &Ident) -> Option<&Import> {
51 self.imports.iter().find(|&e| e == name)
52 }
53
54 fn import_by_id(&self, name: &Ident) -> &Import {
55 self.get_import_by_id(name)
56 .unwrap_or_else(|| panic!("[BUG] validation import id missed, cannot find `{name}`: {:#?}",self.imports()))
57 }
58
59 pub fn get_import_by_path(&self, path: &LitStr) -> Option<&Import> {
61 let path = path.value();
62 self.imports.iter().find(|&e| e == &*path)
63 }
64
65 pub(crate) fn import_by_path(&self, path: &LitStr) -> &Import {
66 self.get_import_by_path(path).unwrap_or_else(|| {
67 panic!(
68 "[BUG] validation import path missed, cannot find `{}`",
69 path.value()
70 )
71 })
72 }
73
74 pub(crate) fn get_resolved_id(&self, id: &Ident) -> Option<AliasKind<'_>> {
75 match self.get_block(id) {
76 Some(block) => Some(AliasKind::Block(block)),
77 None => Some(AliasKind::Import(self.get_import_by_id(id)?)),
78 }
79 }
80
81 pub(crate) fn resolve_id(&self, id: &Ident) -> AliasKind<'_> {
82 match self.get_block(id) {
83 Some(block) => AliasKind::Block(block),
84 None => AliasKind::Import(self.import_by_id(id)),
85 }
86 }
87
88 pub fn stmts(&self) -> &[StmtTempl] {
90 &self.stmts
91 }
92
93 pub fn stmts_mut(&mut self) -> &mut Vec<StmtTempl> {
95 &mut self.stmts
96 }
97
98 pub fn imports(&self) -> &[Import] {
99 &self.imports
100 }
101
102 pub fn blocks(&self) -> &[BlockContent] {
103 &self.blocks
104 }
105
106 pub fn blocks_mut(&mut self) -> &mut Vec<BlockContent> {
107 &mut self.blocks
108 }
109
110 pub fn statics(&self) -> &[Rc<str>] {
111 &self.statics
112 }
113
114 pub fn layout(&self) -> Option<&LayoutTempl> {
115 self.layout.as_ref()
116 }
117}
118
119#[derive(Debug)]
122pub struct Import {
123 path: Rc<str>,
124 alias: Ident,
125 templ: Template,
126}
127
128impl Import {
129 pub fn path(&self) -> &str {
130 &self.path
131 }
132
133 pub fn alias(&self) -> &Ident {
134 &self.alias
135 }
136
137 pub fn templ(&self) -> &Template {
138 &self.templ
139 }
140}
141
142impl PartialEq<str> for Import {
143 fn eq(&self, other: &str) -> bool {
144 self.path.as_ref() == other
145 }
146}
147
148impl PartialEq<Ident> for Import {
149 fn eq(&self, other: &Ident) -> bool {
150 &self.alias == other
151 }
152}
153
154pub enum AliasKind<'a> {
157 Block(&'a BlockContent),
158 Import(&'a Import),
159}
160
161impl std::fmt::Debug for File {
164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 f.debug_struct("File")
166 .field("layout", &self.layout.as_ref().map(|e|e.path.value()))
167 .field("imports", &self.imports)
168 .field("blocks", &self.blocks)
169 .field("statics", &self.statics)
170 .field("stmts", &"<statements>")
171 .finish()
172 }
173}
174
175impl std::fmt::Debug for BlockContent {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 f.debug_struct("BlockContent")
178 .field("templ", &self.templ.name)
179 .field("stmts", &"<statements>")
180 .finish()
181 }
182}
183