Compare commits
3 Commits
89a7780d10
...
d1883ff3ab
Author | SHA1 | Date | |
---|---|---|---|
|
d1883ff3ab | ||
|
2a560cfcef | ||
|
c2800dfcc7 |
131
src/main.rs
131
src/main.rs
@ -10,6 +10,7 @@ enum Token
|
||||
{
|
||||
StringLit(String, i32, i32),
|
||||
IntLit(String, i32, i32),
|
||||
BoolLit(String, i32, i32),
|
||||
Keyword(String, i32, i32),
|
||||
}
|
||||
|
||||
@ -26,6 +27,7 @@ enum Datatype
|
||||
{
|
||||
Int,
|
||||
String,
|
||||
Bool,
|
||||
//Pointer,
|
||||
Any,
|
||||
}
|
||||
@ -54,7 +56,10 @@ 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),
|
||||
@ -67,6 +72,11 @@ 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
|
||||
@ -132,6 +142,18 @@ 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);
|
||||
@ -140,7 +162,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
||||
{
|
||||
let val = queue.remove(0);
|
||||
// TODO: Add bool type
|
||||
if val == "0"
|
||||
if val == "true"
|
||||
{
|
||||
interpret_program(if_block, queue, functions, intrinsics, debug);
|
||||
}
|
||||
@ -163,6 +185,36 @@ 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);
|
||||
@ -173,8 +225,8 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
||||
{
|
||||
loop
|
||||
{
|
||||
let val = queue.get(0).unwrap();
|
||||
if val == "0"
|
||||
let val = queue.remove(0);
|
||||
if val == "false"
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -227,6 +279,8 @@ 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) |
|
||||
@ -265,6 +319,17 @@ 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()
|
||||
@ -274,6 +339,21 @@ 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();
|
||||
@ -298,9 +378,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::Int
|
||||
if comparison_type != Datatype::Bool
|
||||
{
|
||||
panic!("Expected an int as an if condition but got {:?} instead at {}:{}", comparison_type, line, col);
|
||||
panic!("Expected a Bool as an if condition but got {:?} instead at {}:{}", comparison_type, line, col);
|
||||
}
|
||||
if debug
|
||||
{
|
||||
@ -350,16 +430,18 @@ 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.get(0).unwrap();
|
||||
if comparison_type != Datatype::Int
|
||||
let comparison_type = type_queue.remove(0);
|
||||
if comparison_type != Datatype::Bool
|
||||
{
|
||||
panic!("Expected an int as a while condition but got {:?} instead at {}:{}", comparison_type, line, col);
|
||||
panic!("Expected a Bool as a while condition but got {:?} instead at {}:{}", comparison_type, line, col);
|
||||
}
|
||||
if debug
|
||||
{
|
||||
println!("Starting to typecheck while block");
|
||||
}
|
||||
typecheck_block(while_block, type_queue, type_queue, functions, intrinsics, debug);
|
||||
let mut outs = type_queue.clone();
|
||||
outs.insert(0, Datatype::Bool);
|
||||
typecheck_block(while_block, type_queue, &outs, functions, intrinsics, debug);
|
||||
}
|
||||
}
|
||||
if debug
|
||||
@ -393,12 +475,12 @@ fn validate_function_calls_in_block(block: &Vec<Operation>, functions: &Vec<Func
|
||||
{
|
||||
match operation
|
||||
{
|
||||
Operation::Intrinsic(_, _, _) | Operation::Enqueue(_, _, _, _) | Operation::Dequeue(_, _) | Operation::Requeue(_, _) => {},
|
||||
Operation::Intrinsic(_, _, _) | Operation::Enqueue(_, _, _, _) | Operation::Dequeue(_, _) | Operation::Requeue(_, _) | Operation::Dup(_, _) | Operation::Swap(_, _) => {},
|
||||
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, _, _) =>
|
||||
@ -442,7 +524,7 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
||||
{
|
||||
match token
|
||||
{
|
||||
Token::IntLit(_, line, col) | Token::StringLit(_, line, col) =>
|
||||
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);
|
||||
}
|
||||
@ -457,6 +539,7 @@ 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)
|
||||
}
|
||||
}
|
||||
@ -479,7 +562,7 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
||||
{
|
||||
match token
|
||||
{
|
||||
Token::IntLit(_, line, col) | Token::StringLit(_, line, col) =>
|
||||
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);
|
||||
}
|
||||
@ -490,7 +573,8 @@ 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),
|
||||
"{" | "}" | "deq" | "req" => panic!("Expected function name but got {} at {}:{}", word, line, col),
|
||||
"bool" => ins.push(Datatype::Bool),
|
||||
"{" | "}" | "deq" | "req" | "dup" | "swp" | "true" | "false" => panic!("Expected function name but got {} at {}:{}", word, line, col),
|
||||
_ =>
|
||||
{
|
||||
if functions.iter().any(|x| &x.name == word)
|
||||
@ -568,6 +652,10 @@ 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())
|
||||
@ -606,9 +694,16 @@ 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;
|
||||
@ -692,7 +787,7 @@ fn tokenize(text: &str) -> Vec<Token>
|
||||
if ch == '"'
|
||||
{
|
||||
state = TokenizerState::Whitespace;
|
||||
tokens.push(Token::StringLit(word.clone(), line, col));
|
||||
tokens.push(Token::StringLit(word.clone().replace("\\n", "\n"), line, col));
|
||||
word.clear();
|
||||
}
|
||||
else
|
||||
@ -709,6 +804,10 @@ 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));
|
||||
|
13
tests/recursion.qbl
Normal file
13
tests/recursion.qbl
Normal file
@ -0,0 +1,13 @@
|
||||
function int int int => int fibonacci
|
||||
{
|
||||
dup if
|
||||
{
|
||||
req deq deq
|
||||
}
|
||||
else
|
||||
{
|
||||
1 dup + - swp fibonacci
|
||||
}
|
||||
}
|
||||
|
||||
20 1 0 fibonacci print
|
7
tests/req_impl.qbl
Normal file
7
tests/req_impl.qbl
Normal file
@ -0,0 +1,7 @@
|
||||
function int int => int int req_impl
|
||||
{
|
||||
dup deq
|
||||
}
|
||||
|
||||
1 2 3 req_impl print print print
|
||||
1 2 3 req print print print
|
@ -1,5 +1,6 @@
|
||||
//valid
|
||||
//output: Hello, World!\n4242test2Falsetesttesttest
|
||||
//output: Hello, World!
|
||||
//4242test2Falsetesttesttest
|
||||
|
||||
"Hello, World!\n" print 43 foo foo deq
|
||||
|
||||
@ -10,12 +11,12 @@ function any => int foo
|
||||
deq 42 17 print
|
||||
}
|
||||
|
||||
"test2" print 1
|
||||
"test2" print false
|
||||
check
|
||||
print
|
||||
|
||||
|
||||
function int => str check
|
||||
function bool => str check
|
||||
{
|
||||
if
|
||||
{
|
||||
@ -29,9 +30,12 @@ function int => str check
|
||||
|
||||
function int => whileFunction
|
||||
{
|
||||
while
|
||||
dup
|
||||
0 req >
|
||||
req while
|
||||
{
|
||||
1 - "test" req print
|
||||
1 - 0 dup >
|
||||
"test" req req print req
|
||||
}
|
||||
deq
|
||||
}
|
||||
|
21
tests/while.qbl
Normal file
21
tests/while.qbl
Normal file
@ -0,0 +1,21 @@
|
||||
//valid,output:10987654321
|
||||
|
||||
true while
|
||||
{
|
||||
false
|
||||
}
|
||||
|
||||
10 0 dup > req
|
||||
while
|
||||
{
|
||||
dup print
|
||||
|
||||
1 - 0 dup > req
|
||||
}
|
||||
deq
|
||||
|
||||
true true true while
|
||||
{
|
||||
false
|
||||
}
|
||||
print print
|
Reference in New Issue
Block a user