|
|
|
@ -10,7 +10,6 @@ enum Token
|
|
|
|
|
{
|
|
|
|
|
StringLit(String, i32, i32),
|
|
|
|
|
IntLit(String, i32, i32),
|
|
|
|
|
BoolLit(String, i32, i32),
|
|
|
|
|
Keyword(String, i32, i32),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -27,7 +26,6 @@ enum Datatype
|
|
|
|
|
{
|
|
|
|
|
Int,
|
|
|
|
|
String,
|
|
|
|
|
Bool,
|
|
|
|
|
//Pointer,
|
|
|
|
|
Any,
|
|
|
|
|
}
|
|
|
|
@ -56,10 +54,7 @@ enum Operation
|
|
|
|
|
{
|
|
|
|
|
Enqueue(Datatype, String, i32, i32),
|
|
|
|
|
Dequeue(i32, i32),
|
|
|
|
|
// TODO: req can be implemented in terms of dup and dequeue
|
|
|
|
|
Requeue(i32, i32),
|
|
|
|
|
Swap(i32, i32),
|
|
|
|
|
Dup(i32, i32),
|
|
|
|
|
Intrinsic(String, i32, i32),
|
|
|
|
|
FunctionCall(String, i32, i32),
|
|
|
|
|
If(Vec<Operation>, Option<Vec<Operation>>, i32, i32),
|
|
|
|
@ -72,11 +67,6 @@ fn main()
|
|
|
|
|
[
|
|
|
|
|
("print", (Vec::from([Datatype::Any]), Vec::new())),
|
|
|
|
|
("-", (Vec::from([Datatype::Int, Datatype::Int]), Vec::from([Datatype::Int]))),
|
|
|
|
|
("+", (Vec::from([Datatype::Int, Datatype::Int]), Vec::from([Datatype::Int]))),
|
|
|
|
|
("<", (Vec::from([Datatype::Int, Datatype::Int]), Vec::from([Datatype::Bool]))),
|
|
|
|
|
(">", (Vec::from([Datatype::Int, Datatype::Int]), Vec::from([Datatype::Bool]))),
|
|
|
|
|
("==", (Vec::from([Datatype::Int, Datatype::Int]), Vec::from([Datatype::Bool]))),
|
|
|
|
|
("!=", (Vec::from([Datatype::Int, Datatype::Int]), Vec::from([Datatype::Bool]))),
|
|
|
|
|
]);
|
|
|
|
|
let args: Vec<String> = env::args().collect();
|
|
|
|
|
if args.len() < 2
|
|
|
|
@ -142,18 +132,6 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
let val = queue.remove(0);
|
|
|
|
|
queue.push(val);
|
|
|
|
|
}
|
|
|
|
|
Operation::Dup(_, _) =>
|
|
|
|
|
{
|
|
|
|
|
let val = queue.get(0).unwrap();
|
|
|
|
|
queue.push(val.clone());
|
|
|
|
|
}
|
|
|
|
|
Operation::Swap(_, _) =>
|
|
|
|
|
{
|
|
|
|
|
let first = queue.remove(0);
|
|
|
|
|
let second = queue.remove(0);
|
|
|
|
|
queue.push(second);
|
|
|
|
|
queue.push(first);
|
|
|
|
|
}
|
|
|
|
|
Operation::FunctionCall(function_name, _, _) =>
|
|
|
|
|
{
|
|
|
|
|
interpret_program(&functions.iter().find(|x| &x.name == function_name).unwrap().content, queue, functions, intrinsics, debug);
|
|
|
|
@ -162,7 +140,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
{
|
|
|
|
|
let val = queue.remove(0);
|
|
|
|
|
// TODO: Add bool type
|
|
|
|
|
if val == "true"
|
|
|
|
|
if val == "0"
|
|
|
|
|
{
|
|
|
|
|
interpret_program(if_block, queue, functions, intrinsics, debug);
|
|
|
|
|
}
|
|
|
|
@ -185,36 +163,6 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
let subtrahend = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
queue.push((minuend - subtrahend).to_string());
|
|
|
|
|
}
|
|
|
|
|
"+" =>
|
|
|
|
|
{
|
|
|
|
|
let addend1 = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
let addend2 = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
queue.push((addend1 + addend2).to_string());
|
|
|
|
|
}
|
|
|
|
|
">" =>
|
|
|
|
|
{
|
|
|
|
|
let first = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
let second = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
queue.push((first > second).to_string());
|
|
|
|
|
}
|
|
|
|
|
"<" =>
|
|
|
|
|
{
|
|
|
|
|
let first = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
let second = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
queue.push((first < second).to_string());
|
|
|
|
|
}
|
|
|
|
|
"==" =>
|
|
|
|
|
{
|
|
|
|
|
let first = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
let second = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
queue.push((first == second).to_string());
|
|
|
|
|
}
|
|
|
|
|
"!=" =>
|
|
|
|
|
{
|
|
|
|
|
let first = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
let second = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
queue.push((first != second).to_string());
|
|
|
|
|
}
|
|
|
|
|
_ =>
|
|
|
|
|
{
|
|
|
|
|
panic!("Unexpected intrinsic '{}' at {}:{}", intrinsic_name, line, col);
|
|
|
|
@ -225,8 +173,8 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
{
|
|
|
|
|
loop
|
|
|
|
|
{
|
|
|
|
|
let val = queue.remove(0);
|
|
|
|
|
if val == "false"
|
|
|
|
|
let val = queue.get(0).unwrap();
|
|
|
|
|
if val == "0"
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -279,8 +227,6 @@ fn typecheck_block(operations: &Vec<Operation>, ins: &Vec<Datatype>, outs: &Vec<
|
|
|
|
|
{
|
|
|
|
|
Operation::Enqueue(_, _, line, col) |
|
|
|
|
|
Operation::Requeue(line, col) |
|
|
|
|
|
Operation::Dup(line, col) |
|
|
|
|
|
Operation::Swap(line, col) |
|
|
|
|
|
Operation::FunctionCall(_, line, col) |
|
|
|
|
|
Operation::If(_, _, line, col) |
|
|
|
|
|
Operation::Intrinsic(_, line, col) |
|
|
|
|
@ -319,17 +265,6 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
{
|
|
|
|
|
type_queue.push(*datatype);
|
|
|
|
|
}
|
|
|
|
|
Operation::Dup(line, col) =>
|
|
|
|
|
{
|
|
|
|
|
if let Some(typ) = type_queue.get(0)
|
|
|
|
|
{
|
|
|
|
|
type_queue.push(typ.clone());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
panic!("Attempted to dup an element while the queue was empty at {}:{}", line, col);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Operation::Requeue(line, col) =>
|
|
|
|
|
{
|
|
|
|
|
if type_queue.is_empty()
|
|
|
|
@ -339,21 +274,6 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
let typ = type_queue.remove(0);
|
|
|
|
|
type_queue.push(typ);
|
|
|
|
|
}
|
|
|
|
|
Operation::Swap(line, col) =>
|
|
|
|
|
{
|
|
|
|
|
if type_queue.is_empty()
|
|
|
|
|
{
|
|
|
|
|
panic!("Attempted to get the first element for a swap while the queue was empty at {}:{}", line, col);
|
|
|
|
|
}
|
|
|
|
|
let first_typ = type_queue.remove(0);
|
|
|
|
|
if type_queue.is_empty()
|
|
|
|
|
{
|
|
|
|
|
panic!("Attempted to get the second element for a swap while the queue was empty at {}:{}", line, col);
|
|
|
|
|
}
|
|
|
|
|
let second_typ = type_queue.remove(0);
|
|
|
|
|
type_queue.push(second_typ);
|
|
|
|
|
type_queue.push(first_typ);
|
|
|
|
|
}
|
|
|
|
|
Operation::FunctionCall(function_name, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
let function = functions.iter().find(|x| &x.name == function_name).unwrap();
|
|
|
|
@ -378,9 +298,9 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
panic!("Encountered if block with an empty queue at {}:{}", line, col);
|
|
|
|
|
}
|
|
|
|
|
let comparison_type = type_queue.remove(0);
|
|
|
|
|
if comparison_type != Datatype::Bool
|
|
|
|
|
if comparison_type != Datatype::Int
|
|
|
|
|
{
|
|
|
|
|
panic!("Expected a Bool as an if condition but got {:?} instead at {}:{}", comparison_type, line, col);
|
|
|
|
|
panic!("Expected an int as an if condition but got {:?} instead at {}:{}", comparison_type, line, col);
|
|
|
|
|
}
|
|
|
|
|
if debug
|
|
|
|
|
{
|
|
|
|
@ -430,18 +350,16 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
{
|
|
|
|
|
panic!("Encountered while block with an empty queue at {}:{}", line, col);
|
|
|
|
|
}
|
|
|
|
|
let comparison_type = type_queue.remove(0);
|
|
|
|
|
if comparison_type != Datatype::Bool
|
|
|
|
|
let &comparison_type = type_queue.get(0).unwrap();
|
|
|
|
|
if comparison_type != Datatype::Int
|
|
|
|
|
{
|
|
|
|
|
panic!("Expected a Bool as a while condition but got {:?} instead at {}:{}", comparison_type, line, col);
|
|
|
|
|
panic!("Expected an int as a while condition but got {:?} instead at {}:{}", comparison_type, line, col);
|
|
|
|
|
}
|
|
|
|
|
if debug
|
|
|
|
|
{
|
|
|
|
|
println!("Starting to typecheck while block");
|
|
|
|
|
}
|
|
|
|
|
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, type_queue, functions, intrinsics, debug);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if debug
|
|
|
|
@ -475,12 +393,12 @@ fn validate_function_calls_in_block(block: &Vec<Operation>, functions: &Vec<Func
|
|
|
|
|
{
|
|
|
|
|
match operation
|
|
|
|
|
{
|
|
|
|
|
Operation::Intrinsic(_, _, _) | Operation::Enqueue(_, _, _, _) | Operation::Dequeue(_, _) | Operation::Requeue(_, _) | Operation::Dup(_, _) | Operation::Swap(_, _) => {},
|
|
|
|
|
Operation::Intrinsic(_, _, _) | Operation::Enqueue(_, _, _, _) | Operation::Dequeue(_, _) | Operation::Requeue(_, _) => {},
|
|
|
|
|
Operation::FunctionCall(function_name, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
if !functions.iter().any(|x| &x.name == function_name)
|
|
|
|
|
{
|
|
|
|
|
panic!("Call to unknown function '{}' at {}:{}", function_name, line, col);
|
|
|
|
|
panic!("Call to unknown function {} at {}:{}", function_name, line, col);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Operation::If(if_block, maybe_else_block, _, _) =>
|
|
|
|
@ -524,7 +442,7 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
{
|
|
|
|
|
match token
|
|
|
|
|
{
|
|
|
|
|
Token::IntLit(_, line, col) | Token::StringLit(_, line, col) | Token::BoolLit(_, line, col) =>
|
|
|
|
|
Token::IntLit(_, line, col) | Token::StringLit(_, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
panic!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col);
|
|
|
|
|
}
|
|
|
|
@ -539,7 +457,6 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
"any" => ins.push(Datatype::Any),
|
|
|
|
|
"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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -562,7 +479,7 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
{
|
|
|
|
|
match token
|
|
|
|
|
{
|
|
|
|
|
Token::IntLit(_, line, col) | Token::StringLit(_, line, col) | Token::BoolLit(_, line, col) =>
|
|
|
|
|
Token::IntLit(_, line, col) | Token::StringLit(_, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
panic!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col);
|
|
|
|
|
}
|
|
|
|
@ -573,8 +490,7 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
"any" => outs.push(Datatype::Any),
|
|
|
|
|
"str" => outs.push(Datatype::String),
|
|
|
|
|
"int" => outs.push(Datatype::Int),
|
|
|
|
|
"bool" => ins.push(Datatype::Bool),
|
|
|
|
|
"{" | "}" | "deq" | "req" | "dup" | "swp" | "true" | "false" => panic!("Expected function name but got {} at {}:{}", word, line, col),
|
|
|
|
|
"{" | "}" | "deq" | "req" => panic!("Expected function name but got {} at {}:{}", word, line, col),
|
|
|
|
|
_ =>
|
|
|
|
|
{
|
|
|
|
|
if functions.iter().any(|x| &x.name == word)
|
|
|
|
@ -652,10 +568,6 @@ fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, in
|
|
|
|
|
{
|
|
|
|
|
operations.push(Operation::Enqueue(Datatype::String, value.clone(), *line, *col));
|
|
|
|
|
}
|
|
|
|
|
Token::BoolLit(value, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
operations.push(Operation::Enqueue(Datatype::Bool, value.clone(), *line, *col));
|
|
|
|
|
}
|
|
|
|
|
Token::Keyword(word, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
if intrinsics.contains_key(word.as_str())
|
|
|
|
@ -694,16 +606,9 @@ fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, in
|
|
|
|
|
}
|
|
|
|
|
else if word == "req"
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
operations.push(Operation::Requeue(*line, *col));
|
|
|
|
|
}
|
|
|
|
|
else if word == "dup"
|
|
|
|
|
{
|
|
|
|
|
operations.push(Operation::Dup(*line, *col));
|
|
|
|
|
}
|
|
|
|
|
else if word == "swp"
|
|
|
|
|
{
|
|
|
|
|
operations.push(Operation::Swap(*line, *col));
|
|
|
|
|
}
|
|
|
|
|
else if Some(word.as_str()) == delimiter
|
|
|
|
|
{
|
|
|
|
|
return operations;
|
|
|
|
@ -787,7 +692,7 @@ fn tokenize(text: &str) -> Vec<Token>
|
|
|
|
|
if ch == '"'
|
|
|
|
|
{
|
|
|
|
|
state = TokenizerState::Whitespace;
|
|
|
|
|
tokens.push(Token::StringLit(word.clone().replace("\\n", "\n"), line, col));
|
|
|
|
|
tokens.push(Token::StringLit(word.clone(), line, col));
|
|
|
|
|
word.clear();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@ -804,10 +709,6 @@ fn tokenize(text: &str) -> Vec<Token>
|
|
|
|
|
{
|
|
|
|
|
tokens.push(Token::IntLit(word.clone(), line, col));
|
|
|
|
|
}
|
|
|
|
|
else if word == "true" || word == "false"
|
|
|
|
|
{
|
|
|
|
|
tokens.push(Token::BoolLit(word.clone(), line, col));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tokens.push(Token::Keyword(word.clone(), line, col));
|
|
|
|
|