Interpretation timeout

This commit is contained in:
PaddiM8 2020-12-28 19:09:21 +01:00
parent 58bb2fd60f
commit b7153d68b7
4 changed files with 41 additions and 10 deletions

View File

@ -12,15 +12,24 @@ pub struct Context<'a> {
angle_unit: String, angle_unit: String,
precision: u32, precision: u32,
sum_n_value: Option<i128>, sum_n_value: Option<i128>,
timeout: Option<u32>,
start_time: std::time::SystemTime,
} }
impl<'a> Context<'a> { 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<u32>,
) -> Self {
Context { Context {
angle_unit: angle_unit.into(), angle_unit: angle_unit.into(),
symbol_table, symbol_table,
precision, precision,
sum_n_value: None, 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<KalkNum, CalcErr
} }
fn eval_expr(context: &mut Context, expr: &Expr, unit: &str) -> Result<KalkNum, CalcError> { fn eval_expr(context: &mut Context, expr: &Expr, unit: &str) -> Result<KalkNum, CalcError> {
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 { match expr {
Expr::Binary(left, op, right) => eval_binary_expr(context, &left, op, &right, unit), Expr::Binary(left, op, right) => eval_binary_expr(context, &left, op, &right, unit),
Expr::Unary(op, expr) => eval_unary_expr(context, op, expr, unit), Expr::Unary(op, expr) => eval_unary_expr(context, op, expr, unit),
@ -352,7 +367,7 @@ mod tests {
.insert(DEG_RAD_UNIT.clone()) .insert(DEG_RAD_UNIT.clone())
.insert(RAD_DEG_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]) context.interpret(vec![stmt])
} }
@ -428,8 +443,8 @@ mod tests {
deg_symbol_table deg_symbol_table
.insert(DEG_RAD_UNIT.clone()) .insert(DEG_RAD_UNIT.clone())
.insert(RAD_DEG_UNIT.clone()); .insert(RAD_DEG_UNIT.clone());
let mut rad_context = Context::new(&mut rad_symbol_table, "rad", 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); let mut deg_context = Context::new(&mut deg_symbol_table, "deg", PRECISION, None);
assert!(cmp( assert!(cmp(
rad_context rad_context
@ -452,7 +467,7 @@ mod tests {
let mut symbol_table = SymbolTable::new(); let mut symbol_table = SymbolTable::new();
symbol_table.insert(var_decl("x", literal(1f64))); 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!( assert_eq!(
context.interpret(vec![stmt]).unwrap().unwrap().to_f64(), context.interpret(vec![stmt]).unwrap().unwrap().to_f64(),
1f64 1f64
@ -473,7 +488,7 @@ mod tests {
fn test_var_decl() { fn test_var_decl() {
let stmt = var_decl("x", literal(1f64)); let stmt = var_decl("x", literal(1f64));
let mut symbol_table = SymbolTable::new(); let mut symbol_table = SymbolTable::new();
Context::new(&mut symbol_table, "rad", PRECISION) Context::new(&mut symbol_table, "rad", PRECISION, None)
.interpret(vec![stmt]) .interpret(vec![stmt])
.unwrap(); .unwrap();
@ -492,7 +507,7 @@ mod tests {
binary(var("x"), TokenKind::Plus, literal(2f64)), 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!( assert_eq!(
context.interpret(vec![stmt]).unwrap().unwrap().to_f64(), context.interpret(vec![stmt]).unwrap().unwrap().to_f64(),
3f64 3f64

View File

@ -24,6 +24,7 @@ pub struct Context {
pos: usize, pos: usize,
symbol_table: SymbolTable, symbol_table: SymbolTable,
angle_unit: String, angle_unit: String,
timeout: Option<u32>,
/// This is true whenever the parser is currently parsing a unit declaration. /// 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. /// 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. /// Unit names are instead treated as variables.
@ -43,6 +44,7 @@ impl Context {
pos: 0, pos: 0,
symbol_table: SymbolTable::new(), symbol_table: SymbolTable::new(),
angle_unit: DEFAULT_ANGLE_UNIT.into(), angle_unit: DEFAULT_ANGLE_UNIT.into(),
timeout: None,
parsing_unit_decl: false, parsing_unit_decl: false,
unit_decl_base_unit: None, unit_decl_base_unit: None,
parsing_identifier_stmt: false, parsing_identifier_stmt: false,
@ -60,6 +62,12 @@ impl Context {
self self
} }
pub fn set_timeout(mut self, timeout: Option<u32>) -> Self {
self.timeout = timeout;
self
}
} }
impl Default for Context { impl Default for Context {
@ -75,6 +83,7 @@ pub enum CalcError {
InvalidNumberLiteral(String), InvalidNumberLiteral(String),
InvalidOperator, InvalidOperator,
InvalidUnit, InvalidUnit,
TimedOut,
UnexpectedToken(TokenKind, TokenKind), UnexpectedToken(TokenKind, TokenKind),
UndefinedFn(String), UndefinedFn(String),
UndefinedVar(String), UndefinedVar(String),
@ -95,8 +104,12 @@ pub fn eval(
context.contains_equal_sign = input.contains("="); context.contains_equal_sign = input.contains("=");
let statements = parse(context, input)?; let statements = parse(context, input)?;
let mut interpreter = let mut interpreter = interpreter::Context::new(
interpreter::Context::new(&mut context.symbol_table, &context.angle_unit, precision); &mut context.symbol_table,
&context.angle_unit,
precision,
context.timeout,
);
interpreter.interpret(statements) interpreter.interpret(statements)
} }

View File

@ -50,7 +50,9 @@ fn default_action(context: &Context) {
} else { } else {
get_env_angle_unit() 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; let precision = context.int_flag("precision").unwrap_or(53isize) as u32;
if let Ok(input_file_path) = context.string_flag("input-file") { if let Ok(input_file_path) = context.string_flag("input-file") {

View File

@ -35,6 +35,7 @@ fn print_calc_err(err: CalcError) {
InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x), InvalidNumberLiteral(x) => format!("Invalid number literal: '{}'.", x),
InvalidOperator => format!("Invalid operator."), InvalidOperator => format!("Invalid operator."),
InvalidUnit => format!("Invalid unit."), InvalidUnit => format!("Invalid unit."),
TimedOut => format!("Operation took too long."),
UnexpectedToken(got, expected) => { UnexpectedToken(got, expected) => {
format!("Unexpected token: '{:?}', expected '{:?}'.", got, expected) format!("Unexpected token: '{:?}', expected '{:?}'.", got, expected)
} }