bean_script/
parser.rs

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}