xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/fend-core-1.4.6/src/eval.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 use std::sync::Arc;
2 
3 use crate::{
4 	ast, error::Interrupt, lexer, parser, result::FResult, scope::Scope, value::Value, Span,
5 };
6 
evaluate_to_value<I: Interrupt>( input: &str, scope: Option<Arc<Scope>>, attrs: Attrs, context: &mut crate::Context, int: &I, ) -> FResult<Value>7 pub(crate) fn evaluate_to_value<I: Interrupt>(
8 	input: &str,
9 	scope: Option<Arc<Scope>>,
10 	attrs: Attrs,
11 	context: &mut crate::Context,
12 	int: &I,
13 ) -> FResult<Value> {
14 	let lex = lexer::lex(input, int);
15 	let mut tokens = vec![];
16 	let mut missing_open_parens: i32 = 0;
17 	for token in lex {
18 		let token = token?;
19 		if matches!(token, lexer::Token::Symbol(lexer::Symbol::CloseParens)) {
20 			missing_open_parens += 1;
21 		}
22 		tokens.push(token);
23 	}
24 	for _ in 0..missing_open_parens {
25 		tokens.insert(0, lexer::Token::Symbol(lexer::Symbol::OpenParens));
26 	}
27 	let parsed = parser::parse_tokens(&tokens)?;
28 	let result = ast::evaluate(parsed, scope, attrs, context, int)?;
29 	Ok(result)
30 }
31 
32 #[derive(Clone, Copy, Eq, PartialEq, Debug)]
33 #[allow(clippy::struct_excessive_bools)]
34 pub(crate) struct Attrs {
35 	pub(crate) debug: bool,
36 	pub(crate) show_approx: bool,
37 	pub(crate) plain_number: bool,
38 	pub(crate) trailing_newline: bool,
39 }
40 
41 impl Default for Attrs {
default() -> Self42 	fn default() -> Self {
43 		Self {
44 			debug: false,
45 			show_approx: true,
46 			plain_number: false,
47 			trailing_newline: true,
48 		}
49 	}
50 }
51 
parse_attrs(mut input: &str) -> (Attrs, &str)52 fn parse_attrs(mut input: &str) -> (Attrs, &str) {
53 	let mut attrs = Attrs::default();
54 	while input.starts_with('@') {
55 		if let Some(remaining) = input.strip_prefix("@debug ") {
56 			attrs.debug = true;
57 			input = remaining;
58 		} else if let Some(remaining) = input.strip_prefix("@noapprox ") {
59 			attrs.show_approx = false;
60 			input = remaining;
61 		} else if let Some(remaining) = input.strip_prefix("@plain_number ") {
62 			attrs.plain_number = true;
63 			input = remaining;
64 		} else if let Some(remaining) = input.strip_prefix("@no_trailing_newline ") {
65 			attrs.trailing_newline = false;
66 			input = remaining;
67 		} else {
68 			break;
69 		}
70 	}
71 	(attrs, input)
72 }
73 
74 /// This also saves the calculation result in a variable `_` and `ans`
evaluate_to_spans<I: Interrupt>( input: &str, scope: Option<Arc<Scope>>, context: &mut crate::Context, int: &I, ) -> FResult<(Vec<Span>, bool, Attrs)>75 pub(crate) fn evaluate_to_spans<I: Interrupt>(
76 	input: &str,
77 	scope: Option<Arc<Scope>>,
78 	context: &mut crate::Context,
79 	int: &I,
80 ) -> FResult<(Vec<Span>, bool, Attrs)> {
81 	let (attrs, input) = parse_attrs(input);
82 	let value = evaluate_to_value(input, scope, attrs, context, int)?;
83 	context.variables.insert("_".to_string(), value.clone());
84 	context.variables.insert("ans".to_string(), value.clone());
85 	Ok((
86 		if attrs.debug {
87 			vec![Span::from_string(format!("{value:?}"))]
88 		} else {
89 			let mut spans = vec![];
90 			value.format(0, &mut spans, attrs, context, int)?;
91 			spans
92 		},
93 		value.is_unit(),
94 		attrs,
95 	))
96 }
97