|
|
|
@ -100,29 +100,53 @@ fn main()
|
|
|
|
|
}
|
|
|
|
|
match args[1].as_str()
|
|
|
|
|
{
|
|
|
|
|
"-t" | "--test" =>
|
|
|
|
|
{
|
|
|
|
|
for f in fs::read_dir(&args[2]).unwrap()
|
|
|
|
|
{
|
|
|
|
|
let f = f.unwrap();
|
|
|
|
|
let file_content = fs::read_to_string(f.path()).unwrap();
|
|
|
|
|
println!("========NOW TESTING '{:?}'========", f.path());
|
|
|
|
|
match compile(file_content, &intrinsics, interpret, debug)
|
|
|
|
|
{
|
|
|
|
|
Ok(()) => println!("\n\n\n---Successfully parsed '{:?}'---", f.path()),
|
|
|
|
|
Err(msg) => println!("ERROR: {}", msg),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
"-c" | "--compile" =>
|
|
|
|
|
{
|
|
|
|
|
let file_content = fs::read_to_string(&args[2]).expect("Could not read the source file");
|
|
|
|
|
let mut tokens: Vec<Token> = tokenize(&file_content);
|
|
|
|
|
println!("---Done tokenizing, got {} tokens---", tokens.len());
|
|
|
|
|
let functions: Vec<Function> = extract_functions(&mut tokens, &intrinsics, debug);
|
|
|
|
|
println!("---Done extracting functions, got {} functions and reduced the token count to {}---", functions.len(), tokens.len());
|
|
|
|
|
let operations = parse_until_delimiter(&mut tokens.iter().peekable(), &intrinsics, None, debug);
|
|
|
|
|
println!("---Done parsing tokens into {} operations---", operations.len());
|
|
|
|
|
validate_function_calls(&operations, &functions, debug);
|
|
|
|
|
println!("---Done validating function calls---");
|
|
|
|
|
typecheck(&operations, &functions, &intrinsics, debug);
|
|
|
|
|
println!("---Done typechecking---");
|
|
|
|
|
if interpret
|
|
|
|
|
match compile(file_content, &intrinsics, interpret, debug)
|
|
|
|
|
{
|
|
|
|
|
println!("---Starting to interpret the program---\n\n");
|
|
|
|
|
interpret_program(&operations, &mut Vec::new(), &functions, &intrinsics, debug);
|
|
|
|
|
Ok(()) => println!("\n\n\n---Successfully parsed '{}'---", args[2]),
|
|
|
|
|
Err(msg) => println!("ERROR: {}", msg),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => panic!("Unknown option {}", args[1])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn compile(file_content: String, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, interpret: bool, debug: bool) -> Result<(), String>
|
|
|
|
|
{
|
|
|
|
|
let mut tokens: Vec<Token> = tokenize(&file_content)?;
|
|
|
|
|
println!("---Done tokenizing, got {} tokens---", tokens.len());
|
|
|
|
|
let functions: Vec<Function> = extract_functions(&mut tokens, &intrinsics, debug)?;
|
|
|
|
|
println!("---Done extracting functions, got {} functions and reduced the token count to {}---", functions.len(), tokens.len());
|
|
|
|
|
let operations = parse_until_delimiter(&mut tokens.iter().peekable(), &intrinsics, None, debug)?;
|
|
|
|
|
println!("---Done parsing tokens into {} operations---", operations.len());
|
|
|
|
|
validate_function_calls(&operations, &functions, debug)?;
|
|
|
|
|
println!("---Done validating function calls---");
|
|
|
|
|
typecheck(&operations, &functions, &intrinsics, debug)?;
|
|
|
|
|
println!("---Done typechecking---");
|
|
|
|
|
if interpret
|
|
|
|
|
{
|
|
|
|
|
println!("---Starting to interpret the program---\n\n");
|
|
|
|
|
interpret_program(&operations, &mut Vec::new(), &functions, &intrinsics, debug);
|
|
|
|
|
}
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool)
|
|
|
|
|
{
|
|
|
|
|
for operation in operations
|
|
|
|
@ -273,7 +297,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool)
|
|
|
|
|
fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<(), String>
|
|
|
|
|
{
|
|
|
|
|
for function in functions
|
|
|
|
|
{
|
|
|
|
@ -281,7 +305,7 @@ fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics:
|
|
|
|
|
{
|
|
|
|
|
println!("Now typechecking function '{}'", function.name);
|
|
|
|
|
}
|
|
|
|
|
typecheck_block(&function.content, &function.ins, &function.outs, functions, intrinsics, debug);
|
|
|
|
|
typecheck_block(&function.content, &function.ins, &function.outs, functions, intrinsics, debug)?;
|
|
|
|
|
if debug
|
|
|
|
|
{
|
|
|
|
|
println!("Successfully typechecked function '{}'", function.name);
|
|
|
|
@ -291,16 +315,17 @@ fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics:
|
|
|
|
|
{
|
|
|
|
|
println!("Now typechecking main operations");
|
|
|
|
|
}
|
|
|
|
|
typecheck_block(operations, &Vec::new(), &Vec::new(), functions, intrinsics, debug);
|
|
|
|
|
typecheck_block(operations, &Vec::new(), &Vec::new(), functions, intrinsics, debug)?;
|
|
|
|
|
if debug
|
|
|
|
|
{
|
|
|
|
|
println!("Successfully typechecked main operations");
|
|
|
|
|
}
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn typecheck_block(operations: &Vec<Operation>, ins: &Vec<Datatype>, outs: &Vec<Datatype>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool)
|
|
|
|
|
fn typecheck_block(operations: &Vec<Operation>, ins: &Vec<Datatype>, outs: &Vec<Datatype>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<(), String>
|
|
|
|
|
{
|
|
|
|
|
let actual_outs = get_return_type(operations, ins, functions, intrinsics, debug);
|
|
|
|
|
let actual_outs = get_return_type(operations, ins, functions, intrinsics, debug)?;
|
|
|
|
|
if &actual_outs != outs
|
|
|
|
|
{
|
|
|
|
|
let (line, col) = match operations.last()
|
|
|
|
@ -324,11 +349,12 @@ fn typecheck_block(operations: &Vec<Operation>, ins: &Vec<Datatype>, outs: &Vec<
|
|
|
|
|
}
|
|
|
|
|
None => (-1, -1)
|
|
|
|
|
};
|
|
|
|
|
panic!("Wrong queue state at the end of a block, expected {:?} but got {:?} at {}:{}", outs, actual_outs, line, col);
|
|
|
|
|
return Err(format!("Wrong queue state at the end of a block, expected {:?} but got {:?} at {}:{}", outs, actual_outs, line, col));
|
|
|
|
|
}
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Vec<Datatype>
|
|
|
|
|
fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<Vec<Datatype>, String>
|
|
|
|
|
{
|
|
|
|
|
let type_queue: &mut Vec<Datatype> = &mut Vec::new();
|
|
|
|
|
type_queue.extend_from_slice(ins);
|
|
|
|
@ -345,7 +371,7 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
{
|
|
|
|
|
if type_queue.is_empty()
|
|
|
|
|
{
|
|
|
|
|
panic!("Attempted to dequeue an element while the queue was empty at {}:{}", line, col);
|
|
|
|
|
return Err(format!("Attempted to dequeue an element while the queue was empty at {}:{}", line, col));
|
|
|
|
|
}
|
|
|
|
|
type_queue.remove(0);
|
|
|
|
|
}
|
|
|
|
@ -361,14 +387,14 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
panic!("Attempted to dup an element while the queue was empty at {}:{}", line, col);
|
|
|
|
|
return Err(format!("Attempted to dup an element while the queue was empty at {}:{}", line, col));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Operation::Requeue(line, col) =>
|
|
|
|
|
{
|
|
|
|
|
if type_queue.is_empty()
|
|
|
|
|
{
|
|
|
|
|
panic!("Attempted to requeue an element while the queue was empty at {}:{}", line, col);
|
|
|
|
|
return Err(format!("Attempted to requeue an element while the queue was empty at {}:{}", line, col));
|
|
|
|
|
}
|
|
|
|
|
let typ = type_queue.remove(0);
|
|
|
|
|
type_queue.push(typ);
|
|
|
|
@ -393,14 +419,14 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
let function = functions.iter().find(|x| &x.name == function_name).unwrap();
|
|
|
|
|
if function.ins.len() > type_queue.len()
|
|
|
|
|
{
|
|
|
|
|
panic!("Attempted to call function '{}' at {}:{}, with insufficient elements in the queue, expected {:?} but got {:?}", function.name, line, col, function.ins, type_queue);
|
|
|
|
|
return Err(format!("Attempted to call function '{}' at {}:{}, with insufficient elements in the queue, expected {:?} but got {:?}", function.name, line, col, function.ins, type_queue));
|
|
|
|
|
}
|
|
|
|
|
for in_type in &function.ins
|
|
|
|
|
{
|
|
|
|
|
let actual_type = type_queue.remove(0);
|
|
|
|
|
if in_type != &actual_type
|
|
|
|
|
{
|
|
|
|
|
panic!("Attempted to call function '{}' at {}:{} with a wrong parameter, expected {:?} but got {:?}", function.name, line, col, in_type, actual_type);
|
|
|
|
|
return Err(format!("Attempted to call function '{}' at {}:{} with a wrong parameter, expected {:?} but got {:?}", function.name, line, col, in_type, actual_type));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
type_queue.extend_from_slice(&function.outs);
|
|
|
|
@ -409,18 +435,18 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
{
|
|
|
|
|
if type_queue.is_empty()
|
|
|
|
|
{
|
|
|
|
|
panic!("Encountered if block with an empty queue at {}:{}", line, col);
|
|
|
|
|
return Err(format!("Encountered if block with an empty queue at {}:{}", line, col));
|
|
|
|
|
}
|
|
|
|
|
let comparison_type = type_queue.remove(0);
|
|
|
|
|
if comparison_type != Datatype::Bool
|
|
|
|
|
{
|
|
|
|
|
panic!("Expected a Bool as an if condition but got {:?} instead at {}:{}", comparison_type, line, col);
|
|
|
|
|
return Err(format!("Expected a Bool as an if condition but got {:?} instead at {}:{}", comparison_type, line, col));
|
|
|
|
|
}
|
|
|
|
|
if debug
|
|
|
|
|
{
|
|
|
|
|
println!("Starting to typecheck if block");
|
|
|
|
|
}
|
|
|
|
|
let if_ret = get_return_type(if_block, &type_queue, functions, intrinsics, debug);
|
|
|
|
|
let if_ret = get_return_type(if_block, &type_queue, functions, intrinsics, debug)?;
|
|
|
|
|
let else_ret =
|
|
|
|
|
if let Some(else_block) = maybe_else_block
|
|
|
|
|
{
|
|
|
|
@ -428,7 +454,7 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
{
|
|
|
|
|
println!("Starting to typecheck else block");
|
|
|
|
|
}
|
|
|
|
|
get_return_type(else_block, &type_queue, functions, intrinsics, debug)
|
|
|
|
|
get_return_type(else_block, &type_queue, functions, intrinsics, debug)?
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@ -436,7 +462,7 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
};
|
|
|
|
|
if if_ret != else_ret
|
|
|
|
|
{
|
|
|
|
|
panic!("Incompatible queue states after if/else construction, expected {:?} but got {:?}", if_ret, else_ret);
|
|
|
|
|
return Err(format!("Incompatible queue states after if/else construction, expected {:?} but got {:?}", if_ret, else_ret));
|
|
|
|
|
}
|
|
|
|
|
type_queue.clear();
|
|
|
|
|
type_queue.extend_from_slice(&if_ret);
|
|
|
|
@ -446,14 +472,14 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
let io = intrinsics.get(intrinsic_name.as_str()).unwrap();
|
|
|
|
|
if io.0.len() > type_queue.len()
|
|
|
|
|
{
|
|
|
|
|
panic!("Attempted to call intrinsic '{}' at {}:{}, with insufficient elements in the queue, expected {:?} but got {:?}", intrinsic_name, line, col, io.0, type_queue);
|
|
|
|
|
return Err(format!("Attempted to call intrinsic '{}' at {}:{}, with insufficient elements in the queue, expected {:?} but got {:?}", intrinsic_name, line, col, io.0, type_queue));
|
|
|
|
|
}
|
|
|
|
|
for in_type in &io.0
|
|
|
|
|
{
|
|
|
|
|
let actual_type = type_queue.remove(0);
|
|
|
|
|
if in_type != &actual_type
|
|
|
|
|
{
|
|
|
|
|
panic!("Attempted to call intrinsic '{}' at {}:{} with a wrong parameter, expected {:?} but got {:?}", intrinsic_name, line, col, in_type, actual_type);
|
|
|
|
|
return Err(format!("Attempted to call intrinsic '{}' at {}:{} with a wrong parameter, expected {:?} but got {:?}", intrinsic_name, line, col, in_type, actual_type));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
type_queue.extend_from_slice(&io.1);
|
|
|
|
@ -462,7 +488,7 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
{
|
|
|
|
|
if type_queue.is_empty()
|
|
|
|
|
{
|
|
|
|
|
panic!("Encountered while block with an empty queue at {}:{}", line, col);
|
|
|
|
|
return Err(format!("Encountered while block with an empty queue at {}:{}", line, col));
|
|
|
|
|
}
|
|
|
|
|
let comparison_type = type_queue.remove(0);
|
|
|
|
|
if comparison_type != Datatype::Bool
|
|
|
|
@ -475,7 +501,7 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
}
|
|
|
|
|
let mut outs = type_queue.clone();
|
|
|
|
|
outs.insert(0, Datatype::Bool);
|
|
|
|
|
typecheck_block(while_block, type_queue, &outs, functions, intrinsics, debug);
|
|
|
|
|
typecheck_block(while_block, type_queue, &outs, functions, intrinsics, debug)?;
|
|
|
|
|
}
|
|
|
|
|
Operation::Depth(_, _) =>
|
|
|
|
|
{
|
|
|
|
@ -491,27 +517,28 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
println!("{} => {:?}", debug_string, type_queue);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return type_queue.clone();
|
|
|
|
|
return Ok(type_queue.clone());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn validate_function_calls(operations: &Vec<Operation>, functions: &Vec<Function>, debug: bool)
|
|
|
|
|
fn validate_function_calls(operations: &Vec<Operation>, functions: &Vec<Function>, debug: bool) -> Result<(), String>
|
|
|
|
|
{
|
|
|
|
|
for function in functions
|
|
|
|
|
{
|
|
|
|
|
validate_function_calls_in_block(&function.content, functions, debug);
|
|
|
|
|
validate_function_calls_in_block(&function.content, functions, debug)?;
|
|
|
|
|
if debug
|
|
|
|
|
{
|
|
|
|
|
println!("Successfully validated function calls in function '{}'", function.name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
validate_function_calls_in_block(operations, functions, debug);
|
|
|
|
|
validate_function_calls_in_block(operations, functions, debug)?;
|
|
|
|
|
if debug
|
|
|
|
|
{
|
|
|
|
|
println!("Successfully validated function calls in main operations");
|
|
|
|
|
}
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn validate_function_calls_in_block(block: &Vec<Operation>, functions: &Vec<Function>, debug: bool)
|
|
|
|
|
fn validate_function_calls_in_block(block: &Vec<Operation>, functions: &Vec<Function>, debug: bool) -> Result<(), String>
|
|
|
|
|
{
|
|
|
|
|
for operation in block
|
|
|
|
|
{
|
|
|
|
@ -523,26 +550,27 @@ fn validate_function_calls_in_block(block: &Vec<Operation>, functions: &Vec<Func
|
|
|
|
|
{
|
|
|
|
|
if !functions.iter().any(|x| &x.name == function_name)
|
|
|
|
|
{
|
|
|
|
|
panic!("Call to unknown function '{}' at {}:{}", function_name, line, col);
|
|
|
|
|
return Err(format!("Call to unknown function '{}' at {}:{}", function_name, line, col));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Operation::If(if_block, maybe_else_block, _, _) =>
|
|
|
|
|
{
|
|
|
|
|
validate_function_calls_in_block(if_block, functions, debug);
|
|
|
|
|
validate_function_calls_in_block(if_block, functions, debug)?;
|
|
|
|
|
if let Some(else_block) = maybe_else_block
|
|
|
|
|
{
|
|
|
|
|
validate_function_calls_in_block(else_block, functions, debug);
|
|
|
|
|
validate_function_calls_in_block(else_block, functions, debug)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Operation::While(while_block, _, _) =>
|
|
|
|
|
{
|
|
|
|
|
validate_function_calls_in_block(while_block, functions, debug);
|
|
|
|
|
validate_function_calls_in_block(while_block, functions, debug)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Vec<Function>
|
|
|
|
|
fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<Vec<Function>, String>
|
|
|
|
|
{
|
|
|
|
|
let mut tokens_iter = tokens.iter().peekable();
|
|
|
|
|
let mut functions: Vec<Function> = Vec::new();
|
|
|
|
@ -569,7 +597,7 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
{
|
|
|
|
|
Token::IntLit(_, line, col) | Token::StringLit(_, line, col) | Token::BoolLit(_, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
panic!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col);
|
|
|
|
|
return Err(format!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col));
|
|
|
|
|
}
|
|
|
|
|
Token::Keyword(word, line, col) =>
|
|
|
|
|
{
|
|
|
|
@ -583,12 +611,12 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
"str" => ins.push(Datatype::String),
|
|
|
|
|
"int" => ins.push(Datatype::Int),
|
|
|
|
|
"bool" => ins.push(Datatype::Bool),
|
|
|
|
|
_ => panic!("Expected input parameters for a function but got {} instead at {}:{}", word, line, col)
|
|
|
|
|
_ => return Err(format!("Expected input parameters for a function but got {} instead at {}:{}", word, line, col))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => panic!("Unexpected end of file while extracting a function")
|
|
|
|
|
None => return Err(format!("Unexpected end of file while extracting a function"))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if debug
|
|
|
|
@ -607,7 +635,7 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
{
|
|
|
|
|
Token::IntLit(_, line, col) | Token::StringLit(_, line, col) | Token::BoolLit(_, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
panic!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col);
|
|
|
|
|
return Err(format!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col));
|
|
|
|
|
}
|
|
|
|
|
Token::Keyword(word, line, col) =>
|
|
|
|
|
{
|
|
|
|
@ -617,22 +645,22 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
"str" => outs.push(Datatype::String),
|
|
|
|
|
"int" => outs.push(Datatype::Int),
|
|
|
|
|
"bool" => outs.push(Datatype::Bool),
|
|
|
|
|
"{" | "}" | "deq" | "req" | "dup" | "swp" | "true" | "false" | "depth" | "???" => panic!("Expected function name but got {} at {}:{}", word, line, col),
|
|
|
|
|
"{" | "}" | "deq" | "req" | "dup" | "swp" | "true" | "false" | "depth" | "???" => return Err(format!("Expected function name but got {} at {}:{}", word, line, col)),
|
|
|
|
|
_ =>
|
|
|
|
|
{
|
|
|
|
|
if functions.iter().any(|x| &x.name == word)
|
|
|
|
|
{
|
|
|
|
|
panic!("Redeclaration of function '{}' at {}:{}", word, line, col);
|
|
|
|
|
return Err(format!("Redeclaration of function '{}' at {}:{}", word, line, col));
|
|
|
|
|
}
|
|
|
|
|
if intrinsics.contains_key(word.as_str())
|
|
|
|
|
{
|
|
|
|
|
panic!("Function name {} at {}:{} is already an intrinsic", word, line, col);
|
|
|
|
|
return Err(format!("Function name {} at {}:{} is already an intrinsic", word, line, col));
|
|
|
|
|
}
|
|
|
|
|
if debug
|
|
|
|
|
{
|
|
|
|
|
println!("outs: {:?}", outs);
|
|
|
|
|
}
|
|
|
|
|
let block = parse_block(&mut tokens_iter, intrinsics, debug);
|
|
|
|
|
let block = parse_block(&mut tokens_iter, intrinsics, debug)?;
|
|
|
|
|
functions.push(Function {name: word.clone(), ins, outs, content: block});
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -640,7 +668,7 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None => panic!("Unexpected end of file while extracting a function")
|
|
|
|
|
None => return Err(format!("Unexpected end of file while extracting a function"))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -656,26 +684,26 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
}
|
|
|
|
|
tokens.clear();
|
|
|
|
|
tokens.extend_from_slice(&new_tokens);
|
|
|
|
|
return functions;
|
|
|
|
|
return Ok(functions);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_block(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Vec<Operation>
|
|
|
|
|
fn parse_block(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<Vec<Operation>, String>
|
|
|
|
|
{
|
|
|
|
|
if let Some(Token::Keyword(word, line, col)) = tokens_iter.next()
|
|
|
|
|
{
|
|
|
|
|
if word != "{"
|
|
|
|
|
{
|
|
|
|
|
panic!("Expected '{{' to open a block but got {} at {}:{}", word, line, col);
|
|
|
|
|
return Err(format!("Expected '{{' to open a block but got {} at {}:{}", word, line, col));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
panic!("Expected '{{' to open a block");
|
|
|
|
|
return Err(format!("Expected '{{' to open a block"));
|
|
|
|
|
}
|
|
|
|
|
return parse_until_delimiter(tokens_iter, intrinsics, Some("}"), debug);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, delimiter: Option<&str>, debug: bool) -> Vec<Operation>
|
|
|
|
|
fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, delimiter: Option<&str>, debug: bool) -> Result<Vec<Operation>, String>
|
|
|
|
|
{
|
|
|
|
|
let mut operations: Vec<Operation> = Vec::new();
|
|
|
|
|
loop
|
|
|
|
@ -707,14 +735,14 @@ fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, in
|
|
|
|
|
}
|
|
|
|
|
else if word == "if"
|
|
|
|
|
{
|
|
|
|
|
let block = parse_block(tokens_iter, intrinsics, debug);
|
|
|
|
|
let block = parse_block(tokens_iter, intrinsics, debug)?;
|
|
|
|
|
let else_block =
|
|
|
|
|
if let Some(Token::Keyword(maybe_else, _, _)) = tokens_iter.peek()
|
|
|
|
|
{
|
|
|
|
|
if maybe_else == "else"
|
|
|
|
|
{
|
|
|
|
|
tokens_iter.next();
|
|
|
|
|
Some(parse_block(tokens_iter, intrinsics, debug))
|
|
|
|
|
Some(parse_block(tokens_iter, intrinsics, debug)?)
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@ -729,7 +757,7 @@ fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, in
|
|
|
|
|
}
|
|
|
|
|
else if word == "while"
|
|
|
|
|
{
|
|
|
|
|
operations.push(Operation::While(parse_block(tokens_iter, intrinsics, debug), *line, *col));
|
|
|
|
|
operations.push(Operation::While(parse_block(tokens_iter, intrinsics, debug)?, *line, *col));
|
|
|
|
|
}
|
|
|
|
|
else if word == "deq"
|
|
|
|
|
{
|
|
|
|
@ -757,11 +785,11 @@ fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, in
|
|
|
|
|
}
|
|
|
|
|
else if Some(word.as_str()) == delimiter
|
|
|
|
|
{
|
|
|
|
|
return operations;
|
|
|
|
|
return Ok(operations);
|
|
|
|
|
}
|
|
|
|
|
else if word == "{" || word == "function"
|
|
|
|
|
{
|
|
|
|
|
panic!("Unexpected keyword {} at {}:{}", word, line, col);
|
|
|
|
|
return Err(format!("Unexpected keyword {} at {}:{}", word, line, col));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@ -774,11 +802,11 @@ fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, in
|
|
|
|
|
{
|
|
|
|
|
if delimiter.is_some()
|
|
|
|
|
{
|
|
|
|
|
panic!("Reached the end of the file while parsing a block")
|
|
|
|
|
return Err(format!("Reached the end of the file while parsing a block"));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return operations;
|
|
|
|
|
return Ok(operations);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -791,7 +819,7 @@ fn usage()
|
|
|
|
|
exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn tokenize(text: &str) -> Vec<Token>
|
|
|
|
|
fn tokenize(text: &str) -> Result<Vec<Token>, String>
|
|
|
|
|
{
|
|
|
|
|
let mut tokens: Vec<Token> = Vec::new();
|
|
|
|
|
let mut line = 1;
|
|
|
|
@ -869,7 +897,7 @@ fn tokenize(text: &str) -> Vec<Token>
|
|
|
|
|
{
|
|
|
|
|
match ch
|
|
|
|
|
{
|
|
|
|
|
'"' => panic!("Having '\"' in the middle of a word is not allowed"),
|
|
|
|
|
'"' => return Err(format!("Having '\"' in the middle of a word is not allowed")),
|
|
|
|
|
_ =>
|
|
|
|
|
{
|
|
|
|
|
word.push(ch);
|
|
|
|
@ -889,7 +917,7 @@ fn tokenize(text: &str) -> Vec<Token>
|
|
|
|
|
{
|
|
|
|
|
TokenizerState::Quote =>
|
|
|
|
|
{
|
|
|
|
|
panic!("Encountered EOF before closing string");
|
|
|
|
|
return Err(format!("Encountered EOF before closing string"));
|
|
|
|
|
}
|
|
|
|
|
TokenizerState::Whitespace | TokenizerState::Comment => {},
|
|
|
|
|
TokenizerState::Keyword =>
|
|
|
|
@ -897,5 +925,5 @@ fn tokenize(text: &str) -> Vec<Token>
|
|
|
|
|
tokens.push(Token::Keyword(word.clone(), line, col));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tokens
|
|
|
|
|
Ok(tokens)
|
|
|
|
|
}
|
|
|
|
|