#[cfg(feature = "py")]
mod py;
#[expect(unused_imports)]
#[cfg(not(feature = "tracing"))]
use log::{debug, error, info, trace, warn};
#[expect(unused_imports)]
#[cfg(feature = "tracing")]
use tracing::{debug, error, info, trace, warn};
fn spawn<F>(future: F) -> tokio::task::JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
#[cfg(feature = "tracing")]
{
use tracing::instrument::WithSubscriber;
tokio::spawn(future.with_current_subscriber())
}
#[cfg(not(feature = "tracing"))]
{
tokio::spawn(future)
}
}
extern crate alloc;
pub mod ast;
pub mod instance;
pub mod parser;
pub mod utlis;
pub mod _impl_display;
mod builder;
mod err;
mod span;
use alloc::borrow::Cow;
use ast::ASTBuilder;
use indexmap::IndexMap;
pub use span::{FileId, ParsedId};
use std::collections::HashMap;
#[derive(Debug)]
pub struct Parsed {
pub top_ids: Vec<span::ParsedId>,
pub id2idx: HashMap<span::FileId, span::ParsedId>,
pub inner: Vec<(span::FileId, ast::ASTBuilder)>,
}
#[derive(Debug)]
pub struct Files {
pub inner: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct Subckt<'s> {
pub name: Cow<'s, str>,
pub ports: Vec<Cow<'s, str>>,
pub params: Vec<ast::KeyValue<'s>>,
pub ast: AST<'s>,
}
#[derive(Debug, Clone, Default)]
pub struct AST<'s> {
pub subckt: IndexMap<String, Subckt<'s>>,
pub instance: Vec<instance::Instance<'s>>,
pub model: Vec<ast::Model<'s>>,
pub param: Vec<ast::KeyValue<'s>>,
pub option: Vec<(Cow<'s, str>, Option<ast::Value<'s>>)>,
pub init_condition: Vec<(Cow<'s, str>, ast::Value<'s>, Option<Cow<'s, str>>)>,
pub nodeset: Vec<(Cow<'s, str>, ast::Value<'s>, Option<Cow<'s, str>>)>,
pub general: Vec<ast::General<'s>>,
pub data: Vec<ast::Data<'s>>,
pub unknwon: Vec<ast::Unknwon<'s>>,
}
impl ast::ASTBuilder {
#[expect(clippy::too_many_arguments)]
fn build<'s>(
&self,
ast: &mut AST<'s>,
has_err: &mut bool,
file_id: &span::FileId,
parsed_id: span::ParsedId,
files: &'s Files,
parsed_id2idx: &HashMap<FileId, ParsedId>,
parsed_inner: &Vec<(FileId, ASTBuilder)>,
) {
use builder::Builder as _;
fn build_local<'s>(
local_ast: &ast::LocalAST,
ast: &mut AST<'s>,
has_err: &mut bool,
file: &'s str,
file_id: &span::FileId,
parsed_id: span::ParsedId,
files: &'s Files,
parsed_id2idx: &HashMap<FileId, ParsedId>,
parsed_inner: &Vec<(FileId, ASTBuilder)>,
) {
fn build_subckt<'s>(
s: &ast::SubcktBuilder,
has_err: &mut bool,
file: &'s str,
file_id: &span::FileId,
parsed_id: span::ParsedId,
files: &'s Files,
parsed_id2idx: &HashMap<FileId, ParsedId>,
parsed_inner: &Vec<(FileId, ASTBuilder)>,
) -> Subckt<'s> {
let mut ast = AST::default();
s.ast.build(
&mut ast,
has_err,
file_id,
parsed_id,
files,
parsed_id2idx,
parsed_inner,
);
Subckt {
name: s.name.build(file),
ports: s.ports.build(file),
params: s.params.build(file),
ast,
}
}
ast.subckt.extend(local_ast.subckt.iter().map(|s| {
let subckt = build_subckt(
s,
has_err,
file,
file_id,
parsed_id,
files,
parsed_id2idx,
parsed_inner,
);
(subckt.name.to_lowercase(), subckt)
}));
ast.instance
.extend(local_ast.instance.iter().map(|b| b.build(file)));
ast.model
.extend(local_ast.model.iter().map(|b| b.build(file)));
ast.param
.extend(local_ast.param.iter().map(|b| b.build(file)));
ast.option
.extend(local_ast.option.iter().map(|b| b.build(file)));
ast.general
.extend(local_ast.general.iter().map(|b| b.build(file)));
ast.data
.extend(local_ast.data.iter().map(|b| b.build(file)));
ast.init_condition
.extend(local_ast.init_condition.iter().map(|b| b.build(file)));
ast.nodeset
.extend(local_ast.nodeset.iter().map(|b| b.build(file)));
ast.unknwon
.extend(local_ast.unknwon.iter().map(|b| b.build(file)));
for e in &local_ast.errors {
e.report(has_err, file_id, file);
}
}
let file = &files.inner[parsed_id.0];
for seg in &self.segments {
match seg {
ast::Segment::Local(local_ast) => {
build_local(
local_ast,
ast,
has_err,
file,
file_id,
parsed_id,
files,
parsed_id2idx,
parsed_inner,
);
}
ast::Segment::Include(ast_res) => {
let ast_res = ast_res.get().unwrap();
match ast_res {
Ok(parsed_id) => {
let (file_id, _ast) = &parsed_inner[parsed_id.0];
_ast.build(
ast,
has_err,
file_id,
*parsed_id,
files,
parsed_id2idx,
parsed_inner,
);
}
Err(e) => {
e.report(has_err, file_id, file);
}
}
}
}
}
}
}
impl Files {
#[inline]
pub fn build(&self, parsed: Parsed) -> (AST<'_>, bool) {
let mut ast = AST::default();
let mut has_err = false;
for top_id in parsed.top_ids {
let (file_id, _ast) = &parsed.inner[top_id.0];
_ast.build(
&mut ast,
&mut has_err,
file_id,
top_id,
self,
&parsed.id2idx,
&parsed.inner,
);
}
(ast, has_err)
}
}