Make interpret fallible, fix applications at end of file, add more checks

This commit is contained in:
0x4261756D 2022-12-22 00:47:41 +01:00
parent 0abc74f043
commit bf4a08e484
1 changed files with 31 additions and 12 deletions

View File

@ -209,7 +209,7 @@ fn compile(file_content: &String, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec
let output = if interpret
{
println!("---Starting to interpret the program---");
Some(interpret_program(&operations, &mut Vec::new(), &functions, &mut arrays, &intrinsics, debug))
Some(interpret_program(&operations, &mut Vec::new(), &functions, &mut arrays, &intrinsics, debug)?)
}
else
{
@ -218,7 +218,7 @@ fn compile(file_content: &String, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec
return Ok(output);
}
fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, functions: &Vec<Function>, arrays: &mut Vec<Arr>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> String
fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, functions: &Vec<Function>, arrays: &mut Vec<Arr>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<String,String>
{
let mut output = String::new();
for operation in operations
@ -263,7 +263,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
let val = queue.remove(0);
function_context.push(val);
}
output += interpret_program(&function.content, function_context, functions, arrays, intrinsics, debug).as_str();
output += interpret_program(&function.content, function_context, functions, arrays, intrinsics, debug)?.as_str();
for val in function_context
{
queue.push(val.to_string());
@ -274,11 +274,11 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
let val = queue.remove(0);
if val == "true"
{
output += interpret_program(if_block, queue, functions, arrays, intrinsics, debug).as_str();
output += interpret_program(if_block, queue, functions, arrays, intrinsics, debug)?.as_str();
}
else if let Some(else_block) = maybe_else_block
{
output += interpret_program(else_block, queue, functions, arrays, intrinsics, debug).as_str();
output += interpret_program(else_block, queue, functions, arrays, intrinsics, debug)?.as_str();
}
}
Operation::Intrinsic(intrinsic_name, line, col) =>
@ -336,7 +336,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
}
_ =>
{
panic!("Unexpected intrinsic '{}' at {}:{}", intrinsic_name, line, col);
return Err(format!("Unexpected intrinsic '{}' at {}:{}", intrinsic_name, line, col));
}
}
}
@ -350,7 +350,11 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
let position: i64 = queue.remove(0).parse::<i64>().unwrap();
if position >= arr.length
{
panic!("Attempted an out of bounds write for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col);
return Err(format!("Attempted an out of bounds write for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col));
}
if position < 0
{
return Err(format!("Attempted an out of bounds write for array {} ({} < 0) at {}:{}", arr.name, position, line, col));
}
arr.data[position as usize] = queue.remove(0);
}
@ -359,7 +363,11 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
let position: i64 = queue.remove(0).parse::<i64>().unwrap();
if position >= arr.length
{
panic!("Attempted an out of bounds read for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col);
return Err(format!("Attempted an out of bounds read for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col));
}
if position < 0
{
return Err(format!("Attempted an out of bounds read for array {} ({} < 0) at {}:{}", arr.name, position, line, col));
}
queue.push(arr.data[position as usize].clone());
}
@ -367,7 +375,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
{
queue.push(arr.length.to_string());
}
_ => panic!("Unexpected application '{}' at {}:{}", word, line, col)
_ => return Err(format!("Unexpected application '{}' at {}:{}", word, line, col))
}
}
Operation::While(while_block, _, _) =>
@ -379,7 +387,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
{
break;
}
output += interpret_program(while_block, queue, functions, arrays, intrinsics, debug).as_str();
output += interpret_program(while_block, queue, functions, arrays, intrinsics, debug)?.as_str();
}
}
Operation::Depth(_, _) =>
@ -397,7 +405,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
println!("after: {:?}: {:?}, '{}'", operation, queue, output);
}
}
return output;
return Ok(output);
}
fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> Result<(), String>
@ -626,6 +634,10 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
return Err(format!("Expected a position for a write application at {}:{}", line, col));
}
let expected_type = arrays.iter().find(|x| &x.name == name).unwrap().datatype;
if type_queue.is_empty()
{
return Err(format!("Expected data for a write application at {}:{}", line, col));
}
let actual_type = type_queue.remove(0);
if actual_type != expected_type
{
@ -1187,7 +1199,14 @@ fn tokenize(text: &str) -> Result<Vec<Token>, String>
TokenizerState::Whitespace | TokenizerState::Comment => {},
TokenizerState::Keyword =>
{
tokens.push(Token::Keyword(word.clone(), line, col));
if application_name.is_empty()
{
tokens.push(Token::Keyword(word.clone(), line, col));
}
else
{
tokens.push(Token::Apply(application_name.clone(), word.clone(), line, col));
}
}
}
Ok(tokens)