Skip to content

Commit 06b43ee

Browse files
committed
adding recursion test
1 parent da18b6f commit 06b43ee

File tree

2 files changed

+126
-0
lines changed

2 files changed

+126
-0
lines changed

src/compile.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,102 @@ pub fn determine_castable(functions: &mut FunctionMap, types: &TypeMap) -> u64 {
520520
num_changed
521521
}
522522

523+
pub fn initialize_terminated<'a>(
524+
functions: &'a FunctionMap<'a>,
525+
) -> (Vec<String>, Vec<FunctionInfo<'a>>) {
526+
let mut term_ret_vec: Vec<String> = Vec::new();
527+
let mut nonterm_ret_vec: Vec<FunctionInfo> = Vec::new();
528+
529+
for func in functions.values() {
530+
let mut is_term = true;
531+
532+
for call in func.original_body {
533+
if let Statement::Call(call) = call {
534+
match call.check_builtin() {
535+
Some(_) => {
536+
continue;
537+
}
538+
None => {
539+
is_term = false;
540+
break;
541+
}
542+
}
543+
}
544+
}
545+
if is_term {
546+
term_ret_vec.push(func.get_cil_name().clone());
547+
} else {
548+
nonterm_ret_vec.push(func.clone());
549+
}
550+
}
551+
552+
(term_ret_vec, nonterm_ret_vec)
553+
}
554+
555+
pub fn search_for_recursion(
556+
terminated_list: &mut Vec<String>,
557+
functions: &mut Vec<FunctionInfo>,
558+
) -> Result<(), CascadeErrors> {
559+
let mut removed: u64 = 1;
560+
while removed > 0 {
561+
removed = 0;
562+
for func in functions.clone().iter_mut() {
563+
let mut is_term = true;
564+
for call in func.original_body {
565+
if let Statement::Call(call) = call {
566+
let mut call_cil_name = call.get_cil_name();
567+
// If we are calling something with this it must be in the same class
568+
// so hand place the class name
569+
if call_cil_name.contains("this-") {
570+
if let Some(class) = func.class {
571+
call_cil_name =
572+
call_cil_name.replace("this-", &(class.name.to_string() + "-"))
573+
} else {
574+
return Err(CascadeErrors::from(ErrorItem::make_compile_or_internal_error(
575+
"Could not determine class for 'this.' function call",
576+
Some(func.declaration_file),
577+
call.get_name_range(),
578+
"Perhaps you meant to place the function in a resource or domain?")));
579+
}
580+
}
581+
582+
if terminated_list.contains(&call_cil_name) {
583+
continue;
584+
}
585+
is_term = false;
586+
}
587+
}
588+
if is_term {
589+
terminated_list.push(func.get_cil_name());
590+
removed += 1;
591+
let index = functions
592+
.iter()
593+
.position(|x| *x.get_cil_name() == func.get_cil_name())
594+
.unwrap();
595+
functions.remove(index);
596+
}
597+
}
598+
}
599+
600+
if !functions.is_empty() {
601+
let mut error: Option<CompileError> = None;
602+
603+
for func in functions {
604+
error = Some(add_or_create_compile_error(
605+
error,
606+
"Recursive Function call found",
607+
func.declaration_file,
608+
func.get_declaration_range().unwrap_or_default(),
609+
"Calls cannot recursively call each other",
610+
));
611+
}
612+
// Unwrap is safe since we need to go through the loop above at least once
613+
return Err(CascadeErrors::from(error.unwrap()));
614+
}
615+
616+
Ok(())
617+
}
618+
523619
pub fn prevalidate_functions(
524620
functions: &mut FunctionMap,
525621
types: &TypeMap,
@@ -531,6 +627,26 @@ pub fn prevalidate_functions(
531627
num_changed = determine_castable(functions, types);
532628
}
533629

630+
let (mut terminated_functions, mut nonterm_functions) = initialize_terminated(functions);
631+
632+
if terminated_functions.is_empty() && !nonterm_functions.is_empty() {
633+
let mut error: Option<CompileError> = None;
634+
635+
for func in functions.values() {
636+
error = Some(add_or_create_compile_error(
637+
error,
638+
"No terminating call found",
639+
func.declaration_file,
640+
func.get_declaration_range().unwrap_or_default(),
641+
"All function calls found in possible recursive loop",
642+
));
643+
}
644+
// Unwrap is safe since we need to go through the loop above at least once
645+
return Err(CascadeErrors::from(error.unwrap()));
646+
}
647+
648+
search_for_recursion(&mut terminated_functions, &mut nonterm_functions)?;
649+
534650
Ok(())
535651
}
536652

src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1401,4 +1401,14 @@ mod tests {
14011401
0,
14021402
);
14031403
}
1404+
1405+
#[test]
1406+
fn invalid_function_recursion_test() {
1407+
error_policy_test!("functions_recursion.cas", 1, ErrorItem::Compile(_));
1408+
}
1409+
1410+
#[test]
1411+
fn invalid_function_noterm_test() {
1412+
error_policy_test!("functions_no_term.cas", 1, ErrorItem::Compile(_));
1413+
}
14041414
}

0 commit comments

Comments
 (0)