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}