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