parse/
parse.rs

1use general_parser::{
2	Adjacency, BinaryOperator, Configuration, Expression, ExpressionRepresentation,
3	TernaryOperator, UnaryOperator,
4};
5
6fn main() {
7	let arg = std::env::args().nth(1);
8
9	if let Some("--interactive") = arg.as_deref() {
10		run_interactive();
11		return;
12	}
13
14	if let Some(path) = std::env::args().nth(1) {
15		let source = std::fs::read_to_string(&path).unwrap();
16		let (configuration, source) = extract_configuration_and_source(&source);
17
18		eprintln!("{configuration:?}");
19
20		let allocator = bumpalo::Bump::new();
21		let expression: Expression<&str> =
22			Expression::from_string(&source, &configuration, &allocator);
23
24		let expression = ExpressionRepresentation(&expression);
25		println!("{source}\n -> {expression}");
26	} else {
27		let configuration = Configuration {
28			binary_operators: vec![
29				BinaryOperator { representation: "*", precedence: 4 },
30				BinaryOperator { representation: "+", precedence: 3 },
31			],
32			..Default::default()
33		};
34
35		let sources: &[&str] = &["(x (a * b) (d * 2 + e))", "(x (a b) (c d e))"];
36
37		for source in sources {
38			let allocator = bumpalo::Bump::new();
39			let expression: Expression<&str> =
40				Expression::from_string(source, &configuration, &allocator);
41			let expression = ExpressionRepresentation(&expression);
42			eprintln!("{source}\n -> {expression}");
43		}
44	}
45}
46
47fn run_interactive() {
48	use std::io::{BufRead, stdin};
49	let stdin = stdin();
50	let mut buf = Vec::new();
51
52	println!("start");
53
54	for line in stdin.lock().lines().map_while(Result::ok) {
55		if line == "close" {
56			if !buf.is_empty() {
57				eprintln!("no end to message {buf:?}");
58			}
59			break;
60		}
61
62		if line == "end" {
63			let output = String::from_utf8_lossy(&buf);
64
65			let (configuration, source) = extract_configuration_and_source(&output);
66
67			// eprintln!("{configuration:?} {source}");
68
69			{
70				let allocator = bumpalo::Bump::new();
71				let expression: Expression<&str> =
72					Expression::from_string(&source, &configuration, &allocator);
73				let expression = ExpressionRepresentation(&expression);
74				println!("{expression}");
75			}
76
77			// if let Err(error) = out {
78			//     println!("Error: {error:?}");
79			// }
80
81			println!("end");
82			buf.clear();
83			continue;
84		}
85
86		buf.extend_from_slice(line.as_bytes());
87		buf.push(b'\n');
88	}
89}
90
91fn extract_configuration_and_source(input: &str) -> (Configuration<'_>, &str) {
92	if let Some((config, source)) = input.split_once("\n---") {
93		let mut configuration = Configuration::default();
94		for line in config.lines().map(str::trim_end) {
95			let (adjacent, rest) = if let Some(rest) = line.strip_suffix(" (adjacent)") {
96				(true, rest)
97			} else {
98				(false, line)
99			};
100
101			if let Some(rest) = line.strip_suffix(" (function)") {
102				configuration.adjacency.as_mut().expect("expected function").functions.push(rest);
103				continue;
104			}
105
106			let (name, rest) = if let Some((name, rest)) = rest.split_once(':')
107				&& name.trim_end().chars().all(is_identifier)
108			{
109				(name.trim_end(), rest)
110			} else {
111				("", rest)
112			};
113
114			let (syntax, precedence) = rest.rsplit_once('#').unwrap_or((rest, "1"));
115			let precedence: u8 = precedence.parse().expect("invalid precedence");
116
117			let parts: Vec<_> = syntax.trim().split('_').map(str::trim).collect();
118			match parts.as_slice() {
119				["", first, part1, part2] => {
120					configuration.postfix_ternary_operators.push(TernaryOperator {
121						name,
122						parts: (first, part1, part2),
123						precedence,
124					});
125				}
126				[first, part1, part2, ""] => {
127					configuration.prefix_ternary_operators.push(TernaryOperator {
128						name,
129						parts: (first, part1, part2),
130						precedence,
131					});
132				}
133				["", binary_operator, ""] => {
134					let operator = BinaryOperator { representation: binary_operator, precedence };
135					if adjacent {
136						configuration.adjacency =
137							Some(Adjacency { operator, functions: Vec::default() });
138					} else {
139						configuration.binary_operators.push(operator);
140					}
141				}
142				["", after] => {
143					configuration
144						.postfix_unary_operators
145						.push(UnaryOperator { representation: after, precedence });
146				}
147				[before, ""] => {
148					configuration
149						.prefix_unary_operators
150						.push(UnaryOperator { representation: before, precedence });
151				}
152				sequence => panic!("unknown sequence {sequence:?}"),
153			}
154		}
155		(configuration, source.trim())
156	} else {
157		(Configuration::default(), input.trim())
158	}
159}
160
161fn is_identifier(chr: char) -> bool {
162	chr.is_alphanumeric() || matches!(chr, '_' | '$')
163}