1use std::cell::Cell;
2
3use crate::{
4 error::{Error, ErrorSource},
5 lexer::Token,
6};
7
8#[derive(Debug, Clone)]
9pub enum Node {
10 FnCall {
11 name: String,
12 parameters: Vec<Box<PosNode>>,
13 body_fn: Option<Box<PosNode>>,
14 },
15 Scope {
16 body: Vec<Box<PosNode>>,
17 },
18 ParameterBlock {
19 body: Vec<Box<PosNode>>,
20 },
21 Program {
22 body: Vec<Box<PosNode>>,
23 },
24 FnAccess {
25 target: Box<PosNode>,
26 call: Box<PosNode>,
27 },
28 Boolean(bool),
29 Number(f64),
30 String(String),
31 Name(String),
32 None,
33}
34
35#[derive(Debug, Clone)]
36pub struct PosNode {
37 pub node: Node,
38 pub ln: usize,
39}
40
41pub fn parse(tokens: Vec<Token>) -> Result<PosNode, Error> {
42 let i = Cell::new(0usize);
43 let line = Cell::new(1usize);
44 let mut body = Vec::new();
45
46 let next = || &tokens[i.replace(i.get() + 1)];
47 let peek = || &tokens[i.get()];
48 let get_ln = || line.get();
49 let new_ln = || line.replace(line.get() + 1);
50
51 fn parse_token<'a>(
52 mut token: &'a Token,
53 next: &dyn Fn() -> &'a Token,
54 peek: &dyn Fn() -> &'a Token,
55 get_ln: &dyn Fn() -> usize,
56 new_ln: &dyn Fn() -> usize,
57 prevent_accessor: bool,
58 ) -> Result<PosNode, Error> {
59 while let Token::LineBreak = token {
60 new_ln();
61 token = next();
62 }
63
64 let node: Node = match token {
65 Token::FnName(name) => {
66 let mut parameters = Vec::new();
67 let mut body_fn = None;
68
69 if let Token::ArgOpen = peek() {
70 next();
71
72 loop {
73 while let Token::LineBreak = peek() {
74 new_ln();
75 next();
76 }
77
78 if let Token::ArgClose = peek() {
79 break;
80 } else if let Token::EOF = peek() {
81 return Err(Error::new(
82 "Unexpected end of file. (expected ')')",
83 ErrorSource::Line(get_ln()),
84 ));
85 }
86
87 let mut body = Vec::new();
88
89 loop {
90 match peek() {
91 Token::ArgSeparator | Token::ArgClose | Token::EOF => {
92 break;
93 }
94 _ => (),
95 }
96 body.push(Box::new(parse_token(
97 next(),
98 &next,
99 &peek,
100 &get_ln,
101 &new_ln,
102 false,
103 )?));
104 }
105
106 if let Token::ArgSeparator = peek() {
107 next();
108 }
109
110 parameters.push(Box::new(PosNode {
111 node: Node::ParameterBlock { body },
112 ln: get_ln(),
113 }));
114 }
115
116 if let Token::ArgClose = peek() {
117 next();
118 }
119 }
120
121 while let Token::LineBreak = peek() {
122 new_ln();
123 next();
124 }
125
126 if let Token::FnBody = peek() {
127 next();
128 body_fn = Some(Box::new(parse_token(
129 next(),
130 &next,
131 &peek,
132 &get_ln,
133 &new_ln,
134 false,
135 )?));
136 }
137
138 while let Token::LineBreak = peek() {
139 new_ln();
140 next();
141 }
142
143 if (if let Token::Accessor = peek() {
144 true
145 } else {
146 false
147 }) && !prevent_accessor
148 {
149 let mut node = PosNode {
150 node: Node::FnCall {
151 name: name.clone(),
152 parameters,
153 body_fn,
154 },
155 ln: get_ln(),
156 };
157
158 while let Token::Accessor = peek() {
159 next();
160
161 while let Token::LineBreak = peek() {
162 new_ln();
163 next();
164 }
165
166 node = PosNode {
167 node: Node::FnAccess {
168 target: Box::new(node),
169 call: Box::new(parse_token(
170 next(),
171 &next,
172 &peek,
173 &get_ln,
174 &new_ln,
175 true,
176 )?),
177 },
178 ln: get_ln(),
179 };
180 }
181
182 node.node
183 } else {
184 Node::FnCall {
185 name: name.clone(),
186 parameters,
187 body_fn,
188 }
189 }
190 }
191 Token::FnBody => {
192 return Err(Error::new(
193 "Unexpected function body.",
194 ErrorSource::Line(get_ln()),
195 ))
196 }
197 Token::ArgSeparator => {
198 return Err(Error::new("Unexpected comma.", ErrorSource::Line(get_ln())));
199 }
200 Token::ArgOpen => {
201 let mut body = Vec::new();
202
203 loop {
204 while let Token::LineBreak = peek() {
205 new_ln();
206 next();
207 }
208
209 if let Token::ArgClose = peek() {
210 break;
211 } else if let Token::EOF = peek() {
212 return Err(Error::new(
213 "Unexpected end of file. (expected ')')",
214 ErrorSource::Line(get_ln()),
215 ));
216 }
217 body.push(Box::new(parse_token(
218 next(),
219 &next,
220 &peek,
221 &get_ln,
222 &new_ln,
223 false,
224 )?));
225 }
226
227 while let Token::LineBreak = peek() {
228 new_ln();
229 next();
230 }
231 if let Token::ArgClose = peek() {
232 next();
233 }
234
235 Node::ParameterBlock { body }
236 }
237 Token::ArgClose => {
238 return Err(Error::new(
239 "Unexpected closing parentheses.",
240 ErrorSource::Line(get_ln()),
241 ))
242 }
243 Token::ScopeOpen => {
244 let mut body = Vec::new();
245
246 loop {
247 while let Token::LineBreak = peek() {
248 new_ln();
249 next();
250 }
251
252 if let Token::ScopeClose = peek() {
253 break;
254 } else if let Token::EOF = peek() {
255 return Err(Error::new(
256 "Unexpected end of file. (expected '}')",
257 ErrorSource::Line(get_ln()),
258 ));
259 }
260 body.push(Box::new(parse_token(
261 next(),
262 &next,
263 &peek,
264 &get_ln,
265 &new_ln,
266 false,
267 )?));
268 }
269
270 if let Token::ScopeClose = peek() {
271 next();
272 }
273
274 Node::Scope { body }
275 }
276 Token::ScopeClose => {
277 return Err(Error::new(
278 "Unexpected closing brace.",
279 ErrorSource::Line(get_ln()),
280 ))
281 }
282 Token::Accessor => {
283 return Err(Error::new(
284 "Unexpected dot operator.",
285 ErrorSource::Line(get_ln()),
286 ))
287 }
288 Token::Boolean(v) => Node::Boolean(*v),
289 Token::Number(v) => Node::Number(*v),
290 Token::String(v) => Node::String(v.clone()),
291 Token::Name(v) => Node::Name(v.clone()),
292 Token::None => Node::None,
293 Token::EOF => {
294 return Err(Error::new(
295 "Unexpected end of input. (How did this happen?)",
296 ErrorSource::Line(get_ln()),
297 ))
298 }
299 Token::LineBreak => {
300 return Err(Error::new(
301 "Unexpected line break. (How did this happen?)",
302 ErrorSource::Line(get_ln()),
303 ))
304 }
305 };
306
307 return Ok(PosNode { node, ln: get_ln() });
308 }
309
310 while i.get() < tokens.len() - 1 {
311 body.push(Box::new(parse_token(
312 next(),
313 &next,
314 &peek,
315 &get_ln,
316 &new_ln,
317 false,
318 )?));
319 }
320
321 Ok(PosNode {
322 node: Node::Program { body },
323 ln: 0,
324 })
325}