From b7153d68b72b48b49743ae22a2a4fe372ad67a3c Mon Sep 17 00:00:00 2001 From: PaddiM8 Date: Mon, 28 Dec 2020 19:09:21 +0100 Subject: [PATCH] Interpretation timeout --- kalk/src/interpreter.rs | 29 ++++++++++++++++++++++------- kalk/src/parser.rs | 17 +++++++++++++++-- kalk_cli/src/main.rs | 4 +++- kalk_cli/src/output.rs | 1 + 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/kalk/src/interpreter.rs b/kalk/src/interpreter.rs index 74b24ec..6a737fc 100644 --- a/kalk/src/interpreter.rs +++ b/kalk/src/interpreter.rs @@ -12,15 +12,24 @@ pub struct Context<'a> { angle_unit: String, precision: u32, sum_n_value: Option, + timeout: Option, + start_time: std::time::SystemTime, } impl<'a> Context<'a> { - pub fn new(symbol_table: &'a mut SymbolTable, angle_unit: &str, precision: u32) -> Self { + pub fn new( + symbol_table: &'a mut SymbolTable, + angle_unit: &str, + precision: u32, + timeout: Option, + ) -> Self { Context { angle_unit: angle_unit.into(), symbol_table, precision, sum_n_value: None, + timeout: timeout, + start_time: std::time::SystemTime::now(), } } @@ -82,6 +91,12 @@ fn eval_expr_stmt(context: &mut Context, expr: &Expr) -> Result Result { + if let (Ok(elapsed), Some(timeout)) = (context.start_time.elapsed(), context.timeout) { + if elapsed.as_secs() >= timeout as u64 { + return Err(CalcError::TimedOut); + } + } + match expr { Expr::Binary(left, op, right) => eval_binary_expr(context, &left, op, &right, unit), Expr::Unary(op, expr) => eval_unary_expr(context, op, expr, unit), @@ -352,7 +367,7 @@ mod tests { .insert(DEG_RAD_UNIT.clone()) .insert(RAD_DEG_UNIT.clone()); - let mut context = Context::new(&mut symbol_table, "rad", PRECISION); + let mut context = Context::new(&mut symbol_table, "rad", PRECISION, None); context.interpret(vec![stmt]) } @@ -428,8 +443,8 @@ mod tests { deg_symbol_table .insert(DEG_RAD_UNIT.clone()) .insert(RAD_DEG_UNIT.clone()); - let mut rad_context = Context::new(&mut rad_symbol_table, "rad", PRECISION); - let mut deg_context = Context::new(&mut deg_symbol_table, "deg", PRECISION); + let mut rad_context = Context::new(&mut rad_symbol_table, "rad", PRECISION, None); + let mut deg_context = Context::new(&mut deg_symbol_table, "deg", PRECISION, None); assert!(cmp( rad_context @@ -452,7 +467,7 @@ mod tests { let mut symbol_table = SymbolTable::new(); symbol_table.insert(var_decl("x", literal(1f64))); - let mut context = Context::new(&mut symbol_table, "rad", PRECISION); + let mut context = Context::new(&mut symbol_table, "rad", PRECISION, None); assert_eq!( context.interpret(vec![stmt]).unwrap().unwrap().to_f64(), 1f64 @@ -473,7 +488,7 @@ mod tests { fn test_var_decl() { let stmt = var_decl("x", literal(1f64)); let mut symbol_table = SymbolTable::new(); - Context::new(&mut symbol_table, "rad", PRECISION) + Context::new(&mut symbol_table, "rad", PRECISION, None) .interpret(vec![stmt]) .unwrap(); @@ -492,7 +507,7 @@ mod tests { binary(var("x"), TokenKind::Plus, literal(2f64)), )); - let mut context = Context::new(&mut symbol_table, "rad", PRECISION); + let mut context = Context::new(&mut symbol_table, "rad", PRECISION, None); assert_eq!( context.interpret(vec![stmt]).unwrap().unwrap().to_f64(), 3f64 diff --git a/kalk/src/parser.rs b/kalk/src/parser.rs index cf38dfd..b92b734 100644 --- a/kalk/src/parser.rs +++ b/kalk/src/parser.rs @@ -24,6 +24,7 @@ pub struct Context { pos: usize, symbol_table: SymbolTable, angle_unit: String, + timeout: Option, /// This is true whenever the parser is currently parsing a unit declaration. /// It is necessary to keep track of this in order to know when to find (figure out) units that haven't been defined yet. /// Unit names are instead treated as variables. @@ -43,6 +44,7 @@ impl Context { pos: 0, symbol_table: SymbolTable::new(), angle_unit: DEFAULT_ANGLE_UNIT.into(), + timeout: None, parsing_unit_decl: false, unit_decl_base_unit: None, parsing_identifier_stmt: false, @@ -60,6 +62,12 @@ impl Context { self } + + pub fn set_timeout(mut self, timeout: Option) -> Self { + self.timeout = timeout; + + self + } } impl Default for Context { @@ -75,6 +83,7 @@ pub enum CalcError { InvalidNumberLiteral(String), InvalidOperator, InvalidUnit, + TimedOut, UnexpectedToken(TokenKind, TokenKind), UndefinedFn(String), UndefinedVar(String), @@ -95,8 +104,12 @@ pub fn eval( context.contains_equal_sign = input.contains("="); let statements = parse(context, input)?; - let mut interpreter = - interpreter::Context::new(&mut context.symbol_table, &context.angle_unit, precision); + let mut interpreter = interpreter::Context::new( + &mut context.symbol_table, + &context.angle_unit, + precision, + context.timeout, + ); interpreter.interpret(statements) } diff --git a/kalk_cli/src/main.rs b/kalk_cli/src/main.rs index 03c90ff..16d44f7 100644 --- a/kalk_cli/src/main.rs +++ b/kalk_cli/src/main.rs @@ -50,7 +50,9 @@ fn default_action(context: &Context) { } else { get_env_angle_unit() }; - let mut parser_context = parser::Context::new().set_angle_unit(&angle_unit); + let mut parser_context = parser::Context::new() + .set_angle_unit(&angle_unit) + .set_timeout(Some(5)); let precision = context.int_flag("precision").unwrap_or(53isize) as u32; if let Ok(input_file_path) = context.string_flag("input-file") { diff --git a/kalk_cli/src/output.rs b/kalk_cli/src/output.rs index dd685ea..29bb93c 100644 --- a/kalk_cli/src/output.rs +++ b/kalk_cli/src/output.rs @@ -35,6 +35,7 @@ fn print_calc_err(err: CalcError) { InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x), InvalidOperator => format!("Invalid operator."), InvalidUnit => format!("Invalid unit."), + TimedOut => format!("Operation took too long."), UnexpectedToken(got, expected) => { format!("Unexpected token: '{:?}', expected '{:?}'.", got, expected) }