1mod _impl_display;
2mod builder;
3mod err;
4pub mod instance;
5pub mod parser;
6
7use alloc::borrow::Cow;
8use builder::{
9 Builder as _,
10 span::{FileId, ParsedId},
11};
12use err::{ParseError, ParseErrorInner};
13use std::collections::HashMap;
14
15#[derive(Debug)]
16pub struct Parsed {
17 pub top_id: ParsedId,
18 pub id2idx: HashMap<FileId, ParsedId>,
19 pub inner: Vec<(FileId, builder::AST)>,
20}
21#[derive(Debug)]
22pub struct Files {
23 pub inner: Vec<String>,
24}
25
26#[derive(Debug, Clone)]
27pub enum Value<'s> {
28 Num(f64),
29 Expr(Cow<'s, str>),
30}
31
32#[derive(Debug, Clone)]
33pub struct KeyValue<'s> {
34 pub k: Cow<'s, str>,
35 pub v: Value<'s>,
36}
37
38#[derive(Debug, Clone)]
39pub enum Token<'s> {
40 KV(KeyValue<'s>),
41 Value(Value<'s>),
42 V(Cow<'s, str>),
43 I(Cow<'s, str>),
44}
45
46#[derive(Debug, Clone)]
53pub struct Subckt<'s> {
54 pub name: Cow<'s, str>,
55 pub ports: Vec<Cow<'s, str>>,
57 pub params: Vec<KeyValue<'s>>,
58 pub ast: AST<'s>,
59}
60
61#[derive(Debug, Clone)]
62pub struct General<'s> {
63 pub cmd: builder::GeneralCmd,
64 pub tokens: Vec<Token<'s>>,
65}
66
67#[derive(Debug, Clone)]
68pub struct Unknwon<'s> {
69 pub cmd: Cow<'s, str>,
70 pub tokens: Vec<Token<'s>>,
71}
72
73#[derive(Debug, Clone)]
74pub struct Model<'s> {
75 pub name: Cow<'s, str>,
76 pub model_type: ModelType<'s>,
77 pub params: Vec<KeyValue<'s>>,
78}
79
80#[derive(Debug, Clone)]
81pub struct Data<'s> {
82 pub name: Cow<'s, str>,
83 pub values: DataValues<'s>,
84}
85#[derive(Debug, Clone)]
86pub enum DataValues<'s> {
87 InlineExpr {
88 params: Vec<Cow<'s, str>>,
89 values: Vec<Value<'s>>,
90 },
91 InlineNum {
92 params: Vec<Cow<'s, str>>,
93 values: Vec<f64>,
94 },
95 MER(),
98 LAM(),
100}
101
102#[expect(clippy::upper_case_acronyms)]
103#[derive(Debug, Clone)]
104pub enum ModelType<'s> {
105 AMP,
107 C,
109 CORE,
111 D,
113 L,
115 NJF,
117 NMOS,
119 NPN,
121 OPT,
123 PJF,
125 PMOS,
127 PNP,
129 R,
131 U,
133 W,
135 S,
137 Unknown(Cow<'s, str>),
138}
139#[expect(clippy::upper_case_acronyms)]
140#[derive(Debug, Clone, Default)]
141pub struct AST<'s> {
142 pub subckt: Vec<Subckt<'s>>,
143 pub instance: Vec<instance::Instance<'s>>,
144 pub model: Vec<Model<'s>>,
145 pub param: Vec<KeyValue<'s>>,
146 pub option: Vec<(Cow<'s, str>, Option<Value<'s>>)>,
147 pub init_condition: Vec<(Cow<'s, str>, Value<'s>, Option<Cow<'s, str>>)>,
152 pub general: Vec<General<'s>>,
153 pub data: Vec<Data<'s>>,
154 pub unknwon: Vec<Unknwon<'s>>,
155}
156
157impl builder::AST {
158 #[expect(clippy::too_many_arguments)]
159 fn build<'s>(
160 &self,
161 ast: &mut AST<'s>,
162 has_err: &mut bool,
163 file_id: &FileId,
164 parsed_id: ParsedId,
165 files: &'s Files,
166 parsed: &Parsed,
167 ) {
168 fn build_local<'s>(
169 local_ast: &builder::LocalAST,
170 ast: &mut AST<'s>,
171 has_err: &mut bool,
172 file: &'s str,
173 file_id: &FileId,
174 parsed_id: ParsedId,
175 files: &'s Files,
176 parsed: &Parsed,
177 ) {
178 fn build_subckt<'s>(
179 s: &builder::Subckt,
180 has_err: &mut bool,
181 file: &'s str,
182 file_id: &FileId,
183 parsed_id: ParsedId,
184 files: &'s Files,
185 parsed: &Parsed,
186 ) -> Subckt<'s> {
187 let mut ast = AST::default();
188 s.ast
189 .build(&mut ast, has_err, file_id, parsed_id, files, parsed);
190 Subckt {
191 name: s.name.build(file),
192 ports: s.ports.build(file),
193 params: s.params.build(file),
194 ast,
195 }
196 }
197 ast.subckt.extend(
198 local_ast
199 .subckt
200 .iter()
201 .map(|s| build_subckt(s, has_err, file, file_id, parsed_id, files, parsed)),
202 );
203 ast.instance
204 .extend(local_ast.instance.iter().map(|b| b.build(file)));
205 ast.model
206 .extend(local_ast.model.iter().map(|b| b.build(file)));
207 ast.param
208 .extend(local_ast.param.iter().map(|b| b.build(file)));
209 ast.option
210 .extend(local_ast.option.iter().map(|b| b.build(file)));
211 ast.general
212 .extend(local_ast.general.iter().map(|b| b.build(file)));
213 ast.data
214 .extend(local_ast.data.iter().map(|b| b.build(file)));
215 ast.init_condition
216 .extend(local_ast.init_condition.iter().map(|b| b.build(file)));
217 ast.unknwon
218 .extend(local_ast.unknwon.iter().map(|b| b.build(file)));
219 for e in &local_ast.errors {
220 e.report(has_err, file_id, file);
221 }
222 }
223 let file = &files.inner[parsed_id.0];
224 for seg in &self.segments {
225 match seg {
226 builder::Segment::Local(local_ast) => {
227 build_local(
228 local_ast, ast, has_err, file, file_id, parsed_id, files, parsed,
229 );
230 }
231 builder::Segment::Include(ast_res) => {
232 let ast_res = ast_res.get().unwrap();
233 match ast_res {
234 Ok(parsed_id) => {
235 let (file_id, _ast) = &parsed.inner[parsed_id.0];
236 _ast.build(ast, has_err, file_id, *parsed_id, files, parsed);
237 }
238 Err(e) => {
239 e.report(has_err, file_id, file);
240 }
241 }
242 }
243 }
244 }
245 }
246}
247
248impl Files {
249 #[inline]
250 pub fn build(&self, parsed: Parsed) -> (AST<'_>, bool) {
251 let mut ast = AST::default();
252 let mut has_err = false;
253 let (file_id, _ast) = &parsed.inner[parsed.top_id.0];
254 _ast.build(
255 &mut ast,
256 &mut has_err,
257 file_id,
258 parsed.top_id,
259 self,
260 &parsed,
261 );
262 (ast, has_err)
263 }
264}