onefig/
visitor.rs

1use std::{path::{self, PathBuf}, fs};
2
3use flexar::prelude::{Position, Lext};
4use hashbrown::HashMap;
5use serde::{Serialize, Deserialize};
6use crate::{errors::{LogicError, RuntimeError}, conff::ConffType, safe_unwrap, lexer::Token, nodes::source_file::SourceFile};
7
8#[derive(Debug)]
9pub struct ActionTree {
10    pub conff_list: Vec<(ConffType, Path, Box<str>)>,
11    pub shell_list: Vec<(Path, Box<[Box<str>]>)>,
12    pub uni_table: ConfHashMap,
13    pub included: Vec<(PathBuf, PathBuf)>,
14}
15
16impl ActionTree {
17    #[inline]
18    pub fn new() -> Self {
19        Self {
20            conff_list: Vec::new(),
21            shell_list: Vec::new(),
22            included: Vec::new(),
23            uni_table: ConfHashMap::new(),
24        }
25    }
26
27    #[inline]
28    pub fn import(&mut self, map: &mut ConfHashMap, path: impl AsRef<path::Path>) {
29        let file = safe_unwrap!(fs::read_to_string(&path) => RT007, path.as_ref().to_string_lossy());
30        let tokens = Token::tokenize(Lext::new(path.as_ref().to_string_lossy().to_string(), &file));
31        let nodes = SourceFile::parse(tokens);
32        nodes.0.into_vec()
33            .into_iter()
34            .for_each(|x| x.visit(self, map, &[]));
35    }
36}
37
38impl Default for ActionTree {
39    #[inline]
40    fn default() -> Self {
41        Self::new()
42    }
43}
44
45pub type ConfHashMap = HashMap<Box<str>, (Position, DbgValue)>;
46pub type Path = Box<[(Position, Box<str>)]>;
47
48pub trait ConfTable {
49    fn set(&mut self, path: &[(Position, Box<str>)], value: DbgValue, pos: Position);
50}
51
52#[derive(Debug, Clone)]
53pub enum DbgValue {
54    String(Box<str>),
55    Int(usize),
56    Path(Path),
57    Bool(bool),
58    List(Box<[(Position, DbgValue)]>),
59    Table(ConfHashMap),
60    Raw(Box<str>),
61}
62
63impl DbgValue {
64    pub fn same_type(&self, other: &DbgValue) -> bool {
65        macro_rules! double_match {
66            ($($pat:pat,)*) => {
67                match (self, other) {
68                    $(($pat, $pat) => true,)*
69                    (DbgValue::Raw(_), _) => true,
70                    _ => false,
71                }
72            }
73        }
74        
75        use DbgValue as D;
76        double_match! {
77            D::Bool(_),
78            D::Int(_),
79            D::String(_),
80            D::Path(_),
81            D::List(_),
82            D::Table(_),
83        }
84    }
85}
86
87#[derive(Debug, Serialize, Deserialize)]
88pub enum Value {
89    String(Box<str>),
90    Int(usize),
91    Path(Box<[Box<str>]>),
92    Bool(bool),
93    List(Box<[Value]>),
94    Table(HashMap<Box<str>, Value>),
95    Raw(Box<str>),
96}
97
98impl From<DbgValue> for Value {
99    fn from(value: DbgValue) -> Self {
100        use DbgValue as D;
101        use Value as V;
102        match value {
103            D::String(x) => V::String(x),
104            D::Int(x) => V::Int(x),
105            D::Path(x) => V::Path(x.into_vec().into_iter().map(|(_, x)| x).collect()),
106            D::Bool(x) => V::Bool(x),
107            D::List(x) => V::List(x.into_vec().into_iter().map(|(_, x)| x.into()).collect()),
108            D::Table(x) => V::Table(x.into_iter().map(|(k, (_, x))| (k, x.into())).collect()),
109            D::Raw(x) => V::Raw(x),
110        }
111    }
112}
113
114pub trait VisitValue {
115    fn visit(self, visitor: &mut ActionTree, scope: &[(Position, Box<str>)]) -> (Position, DbgValue);
116}
117
118pub trait VisitConfig {
119    fn visit(self, visitor: &mut ActionTree, map: &mut ConfHashMap, scope: &[(Position, Box<str>)]);
120}
121
122impl ConfTable for ConfHashMap {
123    #[inline]
124    fn set(&mut self, path: &[(Position, Box<str>)], value: DbgValue, pos: Position) {
125        if path.len() == 1 {
126            match (self.get_mut(&path[0].1), value) {
127                (Some((_, DbgValue::Table(t1))), DbgValue::Table(t2)) => t2.into_iter()
128                    .for_each(|(k, (v_pos, v_value))| if let Some(first) = t1.insert(k.clone(), (v_pos.clone(), v_value)) {
129                        flexar::compiler_error!((LG001, v_pos) k, first.0.0.ln).throw()
130                    }),
131                (Some((first, _)), _) => flexar::compiler_error!((LG001, path[0].0.clone()) path[0].1, first.0.file_name, first.0.ln, first.0.ln_idx).throw(),
132                (None, value) => {self.insert(path[0].1.clone(), (pos.clone(), value));},
133            }; return;
134        }
135
136        match self.get_mut(&path[0].1) {
137            Some((_, DbgValue::Table(x))) => x.set(&path[1..], value, pos),
138            Some((first, _)) => flexar::compiler_error!((LG001, path[0].0.clone()) path[0].1, first.0.file_name, first.0.ln, first.0.ln_idx).throw(),
139            None => {
140                self.insert(path[0].1.clone(), (pos.clone(), DbgValue::Table(ConfHashMap::new())));
141                self.set(path, value, pos);
142            },
143        }
144    }
145}