1use crate::bulletins::handle_value;
2use crate::lexer::Tokens;
3use std::collections::HashMap;
4
5#[derive(Debug, Clone)]
6pub struct Context {
7 pub table_name: Option<String>,
8 pub key_value: HashMap<String, Node>,
9}
10
11impl Context {
12 pub fn get_table(&self) -> Option<&String> {
13 self.table_name.as_ref()
14 }
15 pub fn new(table_name: Option<String>) -> Self {
16 Context {
17 table_name,
18 key_value: HashMap::new(),
19 }
20 }
21 pub fn set_value(&mut self, key: &String, value: Node) {
22 self.key_value.insert(key.to_owned(), value);
23 }
24 pub fn has_context(&self) -> bool {
25 if self.table_name.is_some() {
26 if self.key_value.len() > 0 {
27 true
28 } else {
29 false
30 }
31 } else {
32 false
33 }
34 }
35 pub fn change_context(&mut self, table_name: String) {
36 self.table_name = Some(table_name);
37 self.key_value = HashMap::new();
38 }
39}
40
41#[derive(Debug, Clone)]
42pub enum TomlValue {
43 Int(i64),
44 Floating(f64),
45 String(String),
46 Array(Vec<TomlValue>),
47 Boolean(bool),
48}
49
50#[derive(Debug, Clone)]
51pub enum Node {
52 Value(TomlValue),
53 Table(String),
54}
55
56#[derive(Debug, PartialEq, Eq)]
57pub enum HeadOption<T> {
58 Some(T),
59 None,
60 Head,
61}
62
63impl<T> HeadOption<T> {
64 pub fn is_some(&self) -> bool {
65 if let HeadOption::None = self {
66 false
67 } else {
68 true
69 }
70 }
71}
72
73#[derive(Debug)]
74pub struct Ast {
75 pub child: Vec<Ast>,
76 pub item: HeadOption<Context>,
77}
78
79#[macro_export]
80macro_rules! comp_err {
81 ( $expected : expr , $found : expr) => {
82 panic!(
83 "Compiling error, expected {:?}, found {:?}",
84 $expected, $found
85 );
86 };
87 ( $message : expr) => {
88 panic!($message);
89 };
90}
91
92#[macro_export]
93macro_rules! assert_toml {
94 ( $left : expr , $right : expr) => {
95 if let Some(x) = $left {
96 if x == $right {
97 ()
98 } else {
99 comp_err!($right, x);
100 }
101 }
102 };
103}
104
105impl Node {
106 pub fn get_value(self) -> TomlValue {
107 if let Node::Value(x) = self {
108 x
109 } else {
110 comp_err!("Expected value, found Segment")
111 }
112 }
113 pub fn get_segment(self) -> String {
114 if let Node::Table(x) = self {
115 x
116 } else {
117 comp_err!("Expected table segment, found value")
118 }
119 }
120}
121
122impl Ast {
123 pub fn make(lexemes: Vec<Tokens>) -> Self {
124 let mut peekable = lexemes.into_iter().peekable();
125 let mut head = Ast::new_head();
126 let mut context = Context::new(None);
127 while peekable.peek().is_some() {
128 if let Some(Tokens::Literal(_)) = peekable.peek() {
130 let identifier = peekable.next().unwrap().to_string();
131 if let Some(x) = identifier.chars().nth(0) {
132 if x.is_numeric() {
133 comp_err!("identifier names should not start with numbers");
134 }
135 } else {
136 comp_err!("Invalid identifier name");
137 }
138 assert_toml!(peekable.next(), Tokens::Eq);
140 let value = handle_value(&mut peekable);
141 context.set_value(&identifier, value)
142 }
143 if let Some(Tokens::Hash) = peekable.peek() {
145 peekable.next();
146 while peekable.peek().is_some() {
147 if let Some(Tokens::LineBreak) = peekable.next() {
148 break;
149 }
150 }
151 }
152 if let Some(Tokens::Sbo) = peekable.next() {
154 if let Some(Tokens::Literal(x)) = peekable.next() {
155 if context.has_context() {
156 head.child.push(Ast::new_context(context.clone()));
157 }
158 context.change_context(x);
159 }
160 }
161 }
162 head.child.push(Ast::new_context(context.clone()));
163 head
164 }
165 pub fn new_head() -> Self {
166 Ast {
167 child: Vec::new(),
168 item: HeadOption::Head,
169 }
170 }
171 pub fn new_segment(segment: &String) -> Self {
172 let context = Context::new(Some(segment.to_string()));
173 Ast {
174 child: Vec::new(),
175 item: HeadOption::Some(context),
176 }
177 }
178 pub fn new_context(context: Context) -> Self {
179 Ast {
180 child: Vec::new(),
181 item: HeadOption::Some(context),
182 }
183 }
184 pub fn has_token(&self) -> bool {
185 self.item.is_some()
186 }
187}