summaryrefslogtreecommitdiff
path: root/src/node/parse.rs
blob: 3137e97fedd96994f26bd216f3c30388c9c2c26a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
	Copyright 2023-2024 Gabriel Bjørnager Jensen.

	This file is part of eAS.

	eAS is free software: you can redistribute it
	and/or modify it under the terms of the GNU
	General Public License as published by the Free
	Software Foundation, either version 3 of the
	License, or (at your option) any later version.

	eAS is distributed in the hope that it will
	be useful, but WITHOUT ANY WARRANTY; without
	even the implied warranty of MERCHANTABILITY or
	FITNESS FOR A PARTICULAR PURPOSE. See the GNU
	General Public License for more details.

	You should have received a copy of the GNU
	General Public License along with eAS. If not,
	see <https://www.gnu.org/licenses/>.
*/

use crate::error::Error;
use crate::node::Node;
use crate::source_location::SourceLocation;
use crate::token::Token;

macro_rules! complete_node {
	($nodes: expr, $new_node: expr, $flag: ident) => {{
		$nodes.push($new_node);
		$flag = true;
		continue;
	}};
}

impl Node {
	#[must_use]
	pub fn parse(tokens: &[(SourceLocation, Token)]) -> Result<Vec<Self>, Error> {
		assert!(tokens.len() > 0x0);

		let mut file: Option<&str> = None;

		let mut nodes: Vec<Self> = Vec::new();

		let mut got_end       = false;
		let mut node_complete = true;

		for (location, token) in tokens {
			use Token::*;

			file = Some(location.file());

			match token {
				Word(word) => match word.as_str() {
					| "CODE16"
					| "code16"
					| "THUMB"
					| "thumb"
					=> complete_node!(nodes, Node::Code16, node_complete),

					| "ARM"
					| "arm"
					| "CODE32"
					| "code32"
					=> complete_node!(nodes, Node::Code32, node_complete),

					| "END"
					| "end"
					=> {
						got_end = true;
						complete_node!(nodes, Node::End, node_complete);
					},

					_ => return Err(Error::UnknownMnemonic(word.clone(), location.clone())),
				},

				Return => {
					if !node_complete { return Err(Error::IncompleteNode(location.clone())) };
					continue;
				},

				_ => {},
			};
		}

		if !got_end { return Err(Error::EndOfFile(file.unwrap().to_string())) };

		return Ok(nodes);
	}
}