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,
precision: u32,
sum_n_value: Option<i128>,
timeout: Option<u32>,
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<u32>,
) -> 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<KalkNum, CalcErr
}
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 {
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

View File

@ -24,6 +24,7 @@ pub struct Context {
pos: usize,
symbol_table: SymbolTable,
angle_unit: String,
timeout: Option<u32>,
/// 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<u32>) -> 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)
}

View File

@ -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") {

View File

@ -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)
}