Compare commits

...

13 Commits

Author SHA1 Message Date
8f8f8ffe80 Update README.md 2025-04-07 17:50:32 +02:00
6ed7838a53 [Compiler-Rust]: Vec.get(0) -> Vec.first() 2024-01-02 17:22:36 +01:00
6085eb0d6e Add solution to project euler's problem 3 2023-12-23 22:10:07 +01:00
01c062ce8f Add increment function to the standard library 2023-12-23 22:05:32 +01:00
90d67867cc Fix fasm error when enqueueing ints > 2^32
On x64 the only instruction supporting imm64 is mov rXX,
imm64 so there has to be a special case for those numbers
2023-12-23 22:01:06 +01:00
1f78ad0a7f Progress on Project Euler problems 2023-12-22 22:57:55 +01:00
3440226658 Add newline 2023-12-22 22:19:52 +01:00
1beec6190e Add decrement to the standard library 2023-12-22 22:19:52 +01:00
8478b10210 Simplifications curtesy of clippy 2023-12-22 22:19:52 +01:00
dcfb3147ba Add first project euler problem 2023-07-28 07:05:09 +02:00
b1cb4a0a0e Optimize swp and req with two-item queue 2023-07-28 07:04:39 +02:00
92f7ec405d Add queue overflow check 2023-07-28 04:55:08 +02:00
09ac457b9d Fix names clobbering fasm's "type" keyword 2023-07-28 03:10:57 +02:00
8 changed files with 311 additions and 73 deletions

View File

@ -1,3 +1,5 @@
**Moved to [Codeberg](https://codeberg.org/0x4261756D/kurz)**
# kurz # kurz
Queue based language Queue based language

View File

@ -26,4 +26,4 @@ rules:
- identifier: "\\b(if|else|while)\\b" - identifier: "\\b(if|else|while)\\b"
- special: "\\b(deq|swp|dup|req|depth)\\b" - special: "\\b(deq|swp|dup|req|depth)\\b"
- special: "\\?\\?\\?" - special: "\\?\\?\\?"
- statement: "arr" - statement: "arr"

View File

@ -0,0 +1,55 @@
//valid,4613732
//:END:
import "../std.qbl"
true 1 2 0 0 0
while
{
// a b even_count 0 sum
fib
// even_count 0 sum b a+b
dup ==
// sum b a+b even_count even?
req req req req
if
// sum b a+b even_count
{
req dup
// b a+b even_count sum b
req req deq 3 +
// b a+b even_count sum+b
req req
}
else
{
req req req
}
// even_count sum+b b a+b
decrement 0 req req
// a+b even_count-1 0 sum+b b
check
// even_count-1 0 sum+b b a+b big?
req req req req swp
// even_count-1 0 sum+b b big? a+b
req req req swp
// a+b even_count-1 0 sum+b big? b
req req req req
// big? b a+b even_count-1 0 sum+b
}
deq deq deq deq intToStr println
function int int => int int fib
{
req dup +
}
function int => int nPrint
{
dup intToStr req print
}
function int => int bool check
{
4000000 dup <
}

View File

@ -0,0 +1,56 @@
//valid,6857
//:END:
import "../std.qbl"
600851475143 2 divHasLargerPF 3
while
{
// n p
req dup 2 req req +
// p n p+2
swp req
// n p p+2
divHasLargerPF
// p+2 hasLPF newN
req
}
deq 2 - intToStr println
function int int => bool int divHasLargerPF
{
req dup req divIfDivisible
// n newN
1 req dup
// newN 1 n newN
== req req
// is1 n newN
if
{
false req deq
}
else
{
true deq req
}
}
function int int => int divIfDivisible
{
// p n
dup req dup swp
// p n p n
divmod 0
// p n p/n p%n 0
req req req ==
// p n p/n isDiv
req req req
if
{
deq req divIfDivisible
}
else
{
req deq deq
}
}

View File

@ -0,0 +1,32 @@
//valid,233168
//:END:
import "../std.qbl"
true 3 0
while
{
// i sum
dup check req req +
incAndCheck req
}
deq intToStr println
function int => int check
{
3 dup % 0 req != req
// not_divisible start
if
{
5 dup % 0 req != req
if
{
deq 0
}
}
}
function int => bool int incAndCheck
{
1 + 1000 dup < req
}

View File

@ -141,7 +141,7 @@ fn main()
{ {
print!("---Output---\n'{}'\n", msg); print!("---Output---\n'{}'\n", msg);
} }
let expected = &format!("//valid,{}:END:", maybe_msg.unwrap_or(String::new()).replace("\n", "\n//")); let expected = &format!("//valid,{}:END:", maybe_msg.unwrap_or(String::new()).replace('\n', "\n//"));
if file_content.starts_with(expected) if file_content.starts_with(expected)
{ {
println!("===PASSED==="); println!("===PASSED===");
@ -160,7 +160,7 @@ fn main()
Err(msg) => Err(msg) =>
{ {
println!("ERROR: {}", msg); println!("ERROR: {}", msg);
if file_content.starts_with(&format!("//invalid,{}:END:", msg.replace("\n", "\n//"))) if file_content.starts_with(&format!("//invalid,{}:END:", msg.replace('\n', "\n//")))
{ {
println!("===PASSED==="); println!("===PASSED===");
count += 1; count += 1;
@ -169,7 +169,7 @@ fn main()
{ {
if let Some(index) = file_content.find(":END:") if let Some(index) = file_content.find(":END:")
{ {
let expected = &format!("//invalid,{}:END:", msg.replace("\n", "\n//")); let expected = &format!("//invalid,{}:END:", msg.replace('\n', "\n//"));
let expected_output = file_content[10..index].replace("\n//", "\n"); let expected_output = file_content[10..index].replace("\n//", "\n");
println!("\n===FAILED===\nExpected the output to be\n'{}'\n({})", expected_output, expected); println!("\n===FAILED===\nExpected the output to be\n'{}'\n({})", expected_output, expected);
} }
@ -206,28 +206,28 @@ fn main()
} }
} }
fn compile(file_content: &String, file_path: &str, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, interpret: bool, run: bool, debug: bool) -> Result<Option<String>, String> fn compile(file_content: &str, file_path: &str, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, interpret: bool, run: bool, debug: bool) -> Result<Option<String>, String>
{ {
let mut tokens: Vec<Token> = tokenize(&file_content)?; let mut tokens: Vec<Token> = tokenize(file_content)?;
println!("---Done tokenizing, got {} tokens---", tokens.len()); println!("---Done tokenizing, got {} tokens---", tokens.len());
let mut functions: Vec<Function> = Vec::new(); let mut functions: Vec<Function> = Vec::new();
extract_functions(&mut tokens, &mut functions, &intrinsics, debug)?; extract_functions(&mut tokens, &mut functions, intrinsics, debug)?;
println!("---Done extracting functions, got {} functions and reduced the token count to {}---", functions.len(), tokens.len()); println!("---Done extracting functions, got {} functions and reduced the token count to {}---", functions.len(), tokens.len());
resolve_imports(&mut tokens, &mut functions, file_path, &mut Vec::from([fs::canonicalize(file_path).unwrap()]), intrinsics, debug)?; resolve_imports(&mut tokens, &mut functions, file_path, &mut Vec::from([fs::canonicalize(file_path).unwrap()]), intrinsics, debug)?;
println!("---Done importing files---"); println!("---Done importing files---");
let mut arrays: Vec<Arr> = extract_arrays(&mut tokens, &intrinsics, &functions, debug)?; let mut arrays: Vec<Arr> = extract_arrays(&mut tokens, intrinsics, &functions, debug)?;
println!("---Done extracting arrays, got {} arrays and reduced the token count to {}---", arrays.len(), tokens.len()); println!("---Done extracting arrays, got {} arrays and reduced the token count to {}---", arrays.len(), tokens.len());
let operations = parse_until_delimiter(&mut tokens.iter().peekable(), &intrinsics, None, debug)?; let operations = parse_until_delimiter(&mut tokens.iter().peekable(), intrinsics, None, debug)?;
println!("---Done parsing tokens into {} operations---", operations.len()); println!("---Done parsing tokens into {} operations---", operations.len());
validate_function_calls(&operations, &functions, &arrays, debug)?; validate_function_calls(&operations, &functions, debug)?;
println!("---Done validating function calls---"); println!("---Done validating function calls---");
typecheck(&operations, &functions, &intrinsics, &arrays, debug)?; typecheck(&operations, &functions, intrinsics, &arrays, debug)?;
println!("---Done typechecking---"); println!("---Done typechecking---");
let start = Instant::now(); let start = Instant::now();
let output = if interpret let output = if interpret
{ {
println!("---Starting to interpret the program---"); 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, debug)?)
} }
else else
{ {
@ -235,14 +235,14 @@ fn compile(file_content: &String, file_path: &str, intrinsics: &HashMap<&str, (V
}; };
if !interpret if !interpret
{ {
if let Err(err) = generate_assembly_linux_x64(&operations, &functions, &intrinsics, &arrays, debug) if let Err(err) = generate_assembly_linux_x64(&operations, &functions, &arrays)
{ {
return Err(err.to_string()); return Err(err.to_string());
} }
let mut fasm_process = match Command::new("fasm").arg("out.asm").spawn() let mut fasm_process = match Command::new("fasm").arg("out.asm").spawn()
{ {
Ok(process) => process, Ok(process) => process,
Err(err) => return Err(format!("Fasm process error: {}", err.to_string())), Err(err) => return Err(format!("Fasm process error: {}", err)),
}; };
match fasm_process.wait() match fasm_process.wait()
{ {
@ -292,7 +292,7 @@ fn compile(file_content: &String, file_path: &str, intrinsics: &HashMap<&str, (V
}; };
} }
println!("---Done after {:?}---", start.elapsed()); println!("---Done after {:?}---", start.elapsed());
return Ok(output); Ok(output)
} }
fn resolve_imports(tokens: &mut Vec<Token>, functions: &mut Vec<Function>, file_path: &str, visited_paths: &mut Vec<PathBuf>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<(), String> fn resolve_imports(tokens: &mut Vec<Token>, functions: &mut Vec<Function>, file_path: &str, visited_paths: &mut Vec<PathBuf>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<(), String>
@ -305,6 +305,7 @@ fn resolve_imports(tokens: &mut Vec<Token>, functions: &mut Vec<Function>, file_
{ {
if let Some(Token::StringLit(import_path, _, _)) = tokens_iter.next() if let Some(Token::StringLit(import_path, _, _)) = tokens_iter.next()
{ {
println!("Resolving {}", import_path);
let full_import_path = fs::canonicalize(file_path).map_err(|e| e.to_string())?.parent().unwrap().join(import_path); let full_import_path = fs::canonicalize(file_path).map_err(|e| e.to_string())?.parent().unwrap().join(import_path);
if visited_paths.contains(&full_import_path) if visited_paths.contains(&full_import_path)
{ {
@ -320,7 +321,7 @@ fn resolve_imports(tokens: &mut Vec<Token>, functions: &mut Vec<Function>, file_
{ {
let mut import_tokens: Vec<Token> = tokenize(&file_content)?; let mut import_tokens: Vec<Token> = tokenize(&file_content)?;
println!("--Done tokenizing the imported file at {}:{}, got {} tokens--", line, col, tokens.len()); println!("--Done tokenizing the imported file at {}:{}, got {} tokens--", line, col, tokens.len());
extract_functions(&mut import_tokens, functions, &intrinsics, debug)?; extract_functions(&mut import_tokens, functions, intrinsics, debug)?;
resolve_imports(&mut import_tokens, functions, file_path, visited_paths, intrinsics, debug)?; resolve_imports(&mut import_tokens, functions, file_path, visited_paths, intrinsics, debug)?;
println!("--Now totalling {} functions--", functions.len()); println!("--Now totalling {} functions--", functions.len());
} }
@ -340,7 +341,7 @@ fn resolve_imports(tokens: &mut Vec<Token>, functions: &mut Vec<Function>, file_
} }
tokens.clear(); tokens.clear();
tokens.extend_from_slice(&new_tokens); tokens.extend_from_slice(&new_tokens);
return Ok(()); Ok(())
} }
struct AssemblyData struct AssemblyData
@ -357,7 +358,7 @@ fn merge_assemblies(data: &mut AssemblyData, data2: AssemblyData)
data.strings += data2.strings.as_str(); data.strings += data2.strings.as_str();
} }
const ASSEMBLY_LINUX_X64_QUEUE_LENGTH: u32 = 4096; const ASSEMBLY_LINUX_X64_QUEUE_LENGTH: u32 = 8192;
const ASSEMBLY_LINUX_X64_HEADER: &str = "format ELF64 executable 3\n"; const ASSEMBLY_LINUX_X64_HEADER: &str = "format ELF64 executable 3\n";
const ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE: &str = "\tcmp r12, r13\n\tcmove r12, r14\n\tcmove r13, r14\n"; const ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE: &str = "\tcmp r12, r13\n\tcmove r12, r14\n\tcmove r13, r14\n";
const ASSEMBLY_LINUX_X64_EXIT: &str = "\tmov rax, 60\n\tmov rdi, 0\n\tsyscall\n"; const ASSEMBLY_LINUX_X64_EXIT: &str = "\tmov rax, 60\n\tmov rdi, 0\n\tsyscall\n";
@ -368,7 +369,7 @@ const ASSEMBLY_LINUX_X64_DYNAMIC_DATA_LENGTH: u32 = 16384;
// r14: base // r14: base
// r15: dynamic end // r15: dynamic end
fn generate_assembly_linux_x64(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> Result<(), std::io::Error> fn generate_assembly_linux_x64(operations: &Vec<Operation>, functions: &Vec<Function>, arrays: &Vec<Arr>) -> Result<(), std::io::Error>
{ {
let mut data = AssemblyData let mut data = AssemblyData
{ {
@ -381,11 +382,11 @@ fn generate_assembly_linux_x64(operations: &Vec<Operation>, functions: &Vec<Func
data.arrays += format!("\tarr_{}: rq {}\n", array.name, array.length).as_str(); data.arrays += format!("\tarr_{}: rq {}\n", array.name, array.length).as_str();
} }
data.code += "_start:\n"; data.code += "_start:\n";
merge_assemblies(&mut data, generate_assembly_linux_x64_block(operations, functions, intrinsics, arrays, debug)); merge_assemblies(&mut data, generate_assembly_linux_x64_block(operations, functions, arrays));
data.code += ASSEMBLY_LINUX_X64_EXIT; data.code += ASSEMBLY_LINUX_X64_EXIT;
for function in functions for function in functions
{ {
merge_assemblies(&mut data, generate_assembly_linux_x64_function(function.name.as_str(), &function.content, functions, intrinsics, arrays, debug)); merge_assemblies(&mut data, generate_assembly_linux_x64_function(function.name.as_str(), &function.content, functions, arrays));
} }
if data.code.contains("call intToStr") if data.code.contains("call intToStr")
@ -436,8 +437,24 @@ fn generate_assembly_linux_x64(operations: &Vec<Operation>, functions: &Vec<Func
data.code += "\tmov rdi, -1\n"; data.code += "\tmov rdi, -1\n";
data.code += "\tsyscall\n"; data.code += "\tsyscall\n";
} }
if data.code.contains("exception_queue_read_out_of_bounds")
{
data.strings += "\texception_queue_oob_msg db \"Queue overflow\", 10\n";
data.code += "exception_queue_read_out_of_bounds:\n";
//TODO: report the passed sizes
data.code += "\tmov rax, 1\n";
data.code += "\tmov rdi, 2\n";
// size
data.code += "\tmov rdx, 37\n";
// data
data.code += "\tmov rsi, exception_queue_oob_msg\n";
data.code += "\tsyscall\n";
data.code += "\tmov rax, 60\n";
data.code += "\tmov rdi, -1\n";
data.code += "\tsyscall\n";
}
return fs::write("out.asm", format!("{}{}{}{}", ASSEMBLY_LINUX_X64_HEADER, data.code, data.arrays, data.strings)); fs::write("out.asm", format!("{}{}{}{}", ASSEMBLY_LINUX_X64_HEADER, data.code, data.arrays, data.strings))
} }
fn generate_assembly_linux_x64_array_oob_check(length: i64) -> String fn generate_assembly_linux_x64_array_oob_check(length: i64) -> String
@ -449,10 +466,17 @@ fn generate_assembly_linux_x64_array_oob_check(length: i64) -> String
data += "\tcmp qword rax, 0\n"; data += "\tcmp qword rax, 0\n";
data += "\tjl exception_array_read_out_of_bounds\n"; data += "\tjl exception_array_read_out_of_bounds\n";
data += "\t\t;;Array bounds check over\n"; data += "\t\t;;Array bounds check over\n";
return data.clone(); data.clone()
} }
fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> AssemblyData fn generate_assembly_linux_x64_queue_oob_check() -> String
{
return "\t\t;;Queue bounds check\n".to_string() +
format!("\tcmp qword r13, {}\n", ASSEMBLY_LINUX_X64_QUEUE_LENGTH).as_str() +
"\tjge exception_queue_read_out_of_bounds\n\t\t;;Queue bounds over\n";
}
fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Vec<Function>, arrays: &Vec<Arr>) -> AssemblyData
{ {
let mut data = AssemblyData let mut data = AssemblyData
{ {
@ -477,7 +501,15 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
{ {
Datatype::Int => Datatype::Int =>
{ {
data.code += format!("\tmov qword [queue+8*r13], {}\n", value).as_str(); if value.parse::<i64>().unwrap() > u32::MAX as i64
{
data.code += format!("\tmov rax, {}\n", value).as_str();
data.code += "\tmov qword [queue+8*r13], rax\n";
}
else
{
data.code += format!("\tmov qword [queue+8*r13], {}\n", value).as_str();
}
} }
Datatype::Bool => Datatype::Bool =>
{ {
@ -501,19 +533,39 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
} }
} }
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
Operation::Requeue(line, col) => Operation::Requeue(line, col) =>
{ {
data.code += format!("\t;;req {}:{}\n", line, col).as_str(); data.code += format!("\t;;req {}:{}\n", line, col).as_str();
data.code += "\tmov rax, r13\n";
data.code += "\tsub rax, r12\n";
data.code += "\tcmp rax, 2\n";
data.code += format!("\tje req_{line}_{col}_special\n").as_str();
data.code += "\tmov rax, [queue+8*r12]\n"; data.code += "\tmov rax, [queue+8*r12]\n";
data.code += "\tinc r12\n"; data.code += "\tinc r12\n";
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
data.code += "\tmov [queue+8*r13], rax\n"; data.code += "\tmov [queue+8*r13], rax\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
data.code += format!("\tjmp req_{line}_{col}_end\n").as_str();
data.code += format!("req_{line}_{col}_special:\n").as_str();
data.code += "\tmov qword rax, [queue+8*r12]\n";
data.code += "\tmov qword rdi, [queue+8*r12+8]\n";
data.code += "\tmov qword r12, r14\n";
data.code += "\tmov qword r13, r14\n";
data.code += "\tmov qword [queue+8*r12], rdi\n";
data.code += "\tmov qword [queue+8*r12+8], rax\n";
data.code += "\tadd r13, 2\n";
data.code += format!("req_{line}_{col}_end:\n").as_str();
} }
Operation::Swap(line, col) => Operation::Swap(line, col) =>
{ {
data.code += format!("\t;;swp {}:{}\n", line, col).as_str(); data.code += format!("\t;;swp {}:{}\n", line, col).as_str();
data.code += "\tmov rax, r13\n";
data.code += "\tsub rax, r12\n";
data.code += "\tcmp rax, 2\n";
data.code += format!("\tje swp_{line}_{col}_special\n").as_str();
data.code += "\tmov rax, [queue+8*r12]\n"; data.code += "\tmov rax, [queue+8*r12]\n";
data.code += "\tmov rbx, [queue+8*r12+8]\n"; data.code += "\tmov rbx, [queue+8*r12+8]\n";
data.code += "\tadd r12, 2\n"; data.code += "\tadd r12, 2\n";
@ -521,6 +573,17 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += "\tmov [queue+8*r13], rbx\n"; data.code += "\tmov [queue+8*r13], rbx\n";
data.code += "\tmov [queue+8*r13+8], rax\n"; data.code += "\tmov [queue+8*r13+8], rax\n";
data.code += "\tadd r13, 2\n"; data.code += "\tadd r13, 2\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
data.code += format!("\tjmp swp_{line}_{col}_end\n").as_str();
data.code += format!("swp_{line}_{col}_special:\n").as_str();
data.code += "\tmov qword rax, [queue+8*r12]\n";
data.code += "\tmov qword rdi, [queue+8*r12+8]\n";
data.code += "\tmov qword r12, r14\n";
data.code += "\tmov qword r13, r14\n";
data.code += "\tmov qword [queue+8*r12], rdi\n";
data.code += "\tmov qword [queue+8*r12+8], rax\n";
data.code += "\tadd r13, 2\n";
data.code += format!("swp_{line}_{col}_end:\n").as_str();
} }
Operation::While(while_operations, line, col) => Operation::While(while_operations, line, col) =>
{ {
@ -530,7 +593,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += format!("while_{}_{}:\n", line, col).as_str(); data.code += format!("while_{}_{}:\n", line, col).as_str();
data.code += "\tinc r12\n"; data.code += "\tinc r12\n";
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
merge_assemblies(&mut data, generate_assembly_linux_x64_block(while_operations, functions, intrinsics, arrays, debug)); merge_assemblies(&mut data, generate_assembly_linux_x64_block(while_operations, functions, arrays));
data.code += "\tcmp qword [queue+8*r12], 0\n"; data.code += "\tcmp qword [queue+8*r12], 0\n";
data.code += format!("\tjne while_{}_{}\n", line, col).as_str(); data.code += format!("\tjne while_{}_{}\n", line, col).as_str();
data.code += format!("while_{}_{}_end:\n", line, col).as_str(); data.code += format!("while_{}_{}_end:\n", line, col).as_str();
@ -544,14 +607,14 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += format!("\tje else_{}_{}\n", line, col).as_str(); data.code += format!("\tje else_{}_{}\n", line, col).as_str();
data.code += "\tinc r12\n"; data.code += "\tinc r12\n";
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
merge_assemblies(&mut data, generate_assembly_linux_x64_block(if_operations, functions, intrinsics, arrays, debug)); merge_assemblies(&mut data, generate_assembly_linux_x64_block(if_operations, functions, arrays));
data.code += format!("\tjmp if_{}_{}_end\n", line, col).as_str(); data.code += format!("\tjmp if_{}_{}_end\n", line, col).as_str();
data.code += format!("else_{}_{}:\n", line, col).as_str(); data.code += format!("else_{}_{}:\n", line, col).as_str();
data.code += "\tinc r12\n"; data.code += "\tinc r12\n";
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
if let Some(else_operations) = maybe_else_operations if let Some(else_operations) = maybe_else_operations
{ {
merge_assemblies(&mut data, generate_assembly_linux_x64_block(else_operations, functions, intrinsics, arrays, debug)); merge_assemblies(&mut data, generate_assembly_linux_x64_block(else_operations, functions, arrays));
} }
data.code += format!("if_{}_{}_end:\n", line, col).as_str(); data.code += format!("if_{}_{}_end:\n", line, col).as_str();
} }
@ -561,6 +624,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += "\tmov rax, [queue+8*r12]\n"; data.code += "\tmov rax, [queue+8*r12]\n";
data.code += "\tmov [queue+8*r13], rax\n"; data.code += "\tmov [queue+8*r13], rax\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
Operation::Intrinsic(name, line, col) => Operation::Intrinsic(name, line, col) =>
{ {
@ -616,6 +680,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += "\tcall intToStr\n"; data.code += "\tcall intToStr\n";
data.code += "\tmov [queue+8*r13], rax\n"; data.code += "\tmov [queue+8*r13], rax\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
"-" => "-" =>
{ {
@ -627,6 +692,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += "\tsub rax, rbx\n"; data.code += "\tsub rax, rbx\n";
data.code += "\tmov [queue+8*r13], rax\n"; data.code += "\tmov [queue+8*r13], rax\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
"+" => "+" =>
{ {
@ -638,6 +704,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += "\tadd rax, rbx\n"; data.code += "\tadd rax, rbx\n";
data.code += "\tmov [queue+8*r13], rax\n"; data.code += "\tmov [queue+8*r13], rax\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
"*" => "*" =>
{ {
@ -649,6 +716,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += "\tmul rbx\n"; data.code += "\tmul rbx\n";
data.code += "\tmov [queue+8*r13], rax\n"; data.code += "\tmov [queue+8*r13], rax\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
"divmod" => "divmod" =>
{ {
@ -661,8 +729,10 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += "\tidiv rbx\n"; data.code += "\tidiv rbx\n";
data.code += "\tmov [queue+8*r13], rax\n"; data.code += "\tmov [queue+8*r13], rax\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
data.code += "\tmov [queue+8*r13], rdx\n"; data.code += "\tmov [queue+8*r13], rdx\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
">" => ">" =>
{ {
@ -675,6 +745,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
data.code += "\tmov qword [queue+8*r13], rbx\n"; data.code += "\tmov qword [queue+8*r13], rbx\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
"<" => "<" =>
{ {
@ -687,6 +758,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
data.code += "\tmov qword [queue+8*r13], rbx\n"; data.code += "\tmov qword [queue+8*r13], rbx\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
">=" => ">=" =>
{ {
@ -699,6 +771,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
data.code += "\tmov qword [queue+8*r13], rbx\n"; data.code += "\tmov qword [queue+8*r13], rbx\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
"<=" => "<=" =>
{ {
@ -711,6 +784,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
data.code += "\tmov qword [queue+8*r13], rbx\n"; data.code += "\tmov qword [queue+8*r13], rbx\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
"==" => "==" =>
{ {
@ -723,6 +797,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
data.code += "\tmov qword [queue+8*r13], rbx\n"; data.code += "\tmov qword [queue+8*r13], rbx\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
"!=" => "!=" =>
{ {
@ -735,6 +810,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
data.code += "\tmov qword [queue+8*r13], rbx\n"; data.code += "\tmov qword [queue+8*r13], rbx\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
"&&" => "&&" =>
{ {
@ -745,6 +821,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
data.code += "\tmov [queue+8*r13], rax\n"; data.code += "\tmov [queue+8*r13], rax\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
_ => todo!("intrinsic {} {}:{}", name, line, col) _ => todo!("intrinsic {} {}:{}", name, line, col)
} }
@ -764,6 +841,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += format!("\tmov qword rbx, [arr_{}+8*rax]\n", name).as_str(); data.code += format!("\tmov qword rbx, [arr_{}+8*rax]\n", name).as_str();
data.code += "\tmov qword [queue+8*r13], rbx\n"; data.code += "\tmov qword [queue+8*r13], rbx\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
"write" => "write" =>
{ {
@ -780,6 +858,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
{ {
data.code += format!("\tmov qword [queue+8*r13], {}\n", array.length).as_str(); data.code += format!("\tmov qword [queue+8*r13], {}\n", array.length).as_str();
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
_ => todo!("apply {}", word) _ => todo!("apply {}", word)
} }
@ -795,6 +874,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE; data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
data.code += "\tmov [queue+8*r13], rax\n"; data.code += "\tmov [queue+8*r13], rax\n";
data.code += "\tinc r13\n"; data.code += "\tinc r13\n";
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
} }
data.code += "\t;; move pointers\n"; data.code += "\t;; move pointers\n";
// save the current base // save the current base
@ -832,10 +912,10 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
_ => todo!("{:?}", operation) _ => todo!("{:?}", operation)
} }
} }
return data; data
} }
fn generate_assembly_linux_x64_function(name: &str, operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> AssemblyData fn generate_assembly_linux_x64_function(name: &str, operations: &Vec<Operation>, functions: &Vec<Function>, arrays: &Vec<Arr>) -> AssemblyData
{ {
let mut data = AssemblyData let mut data = AssemblyData
{ {
@ -843,12 +923,12 @@ fn generate_assembly_linux_x64_function(name: &str, operations: &Vec<Operation>,
code: format!("{}:\n", name), code: format!("{}:\n", name),
strings: String::new(), strings: String::new(),
}; };
merge_assemblies(&mut data, generate_assembly_linux_x64_block(operations, functions, intrinsics, arrays, debug)); merge_assemblies(&mut data, generate_assembly_linux_x64_block(operations, functions, arrays));
data.code += "\tret\n"; data.code += "\tret\n";
return data; data
} }
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> fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, functions: &Vec<Function>, arrays: &mut Vec<Arr>, debug: bool) -> Result<String,String>
{ {
let mut output = String::new(); let mut output = String::new();
for operation in operations for operation in operations
@ -874,7 +954,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
} }
Operation::Dup(_, _) => Operation::Dup(_, _) =>
{ {
let val = queue.get(0).unwrap(); let val = queue.first().unwrap();
queue.push(val.clone()); queue.push(val.clone());
} }
Operation::Swap(_, _) => Operation::Swap(_, _) =>
@ -893,7 +973,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
let val = queue.remove(0); let val = queue.remove(0);
function_context.push(val); 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, debug)?.as_str();
for val in function_context for val in function_context
{ {
queue.push(val.to_string()); queue.push(val.to_string());
@ -904,11 +984,11 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
let val = queue.remove(0); let val = queue.remove(0);
if val == "true" if val == "true"
{ {
output += interpret_program(if_block, queue, functions, arrays, intrinsics, debug)?.as_str(); output += interpret_program(if_block, queue, functions, arrays, debug)?.as_str();
} }
else if let Some(else_block) = maybe_else_block 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, debug)?.as_str();
} }
} }
Operation::Intrinsic(intrinsic_name, line, col) => Operation::Intrinsic(intrinsic_name, line, col) =>
@ -917,7 +997,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
{ {
"print" => "print" =>
{ {
output += format!("{}", queue.remove(0)).as_str(); output += queue.remove(0).to_string().as_str();
} }
"-" => "-" =>
{ {
@ -1061,7 +1141,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
{ {
break; break;
} }
output += interpret_program(while_block, queue, functions, arrays, intrinsics, debug)?.as_str(); output += interpret_program(while_block, queue, functions, arrays, debug)?.as_str();
} }
} }
Operation::Depth(_, _) => Operation::Depth(_, _) =>
@ -1080,7 +1160,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
println!("after: {:?}: {:?}, '{}'", operation, queue, output); println!("after: {:?}: {:?}, '{}'", operation, queue, output);
} }
} }
return Ok(output); Ok(output)
} }
fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> Result<(), String> fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> Result<(), String>
@ -1106,10 +1186,10 @@ fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics:
{ {
println!("Successfully typechecked main operations"); println!("Successfully typechecked main operations");
} }
return Ok(()); Ok(())
} }
fn typecheck_block(operations: &Vec<Operation>, ins: &Vec<Datatype>, outs: &Vec<Datatype>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> Result<(), String> fn typecheck_block(operations: &Vec<Operation>, ins: &[Datatype], outs: &Vec<Datatype>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> Result<(), String>
{ {
let actual_outs = get_return_type(operations, ins, functions, intrinsics, arrays, debug)?; let actual_outs = get_return_type(operations, ins, functions, intrinsics, arrays, debug)?;
if &actual_outs != outs if &actual_outs != outs
@ -1139,10 +1219,10 @@ fn typecheck_block(operations: &Vec<Operation>, ins: &Vec<Datatype>, outs: &Vec<
}; };
return Err(format!("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(()); Ok(())
} }
fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> Result<Vec<Datatype>, String> fn get_return_type(operations: &Vec<Operation>, ins: &[Datatype], functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, arrays: &Vec<Arr>, debug: bool) -> Result<Vec<Datatype>, String>
{ {
let type_queue: &mut Vec<Datatype> = &mut Vec::new(); let type_queue: &mut Vec<Datatype> = &mut Vec::new();
type_queue.extend_from_slice(ins); type_queue.extend_from_slice(ins);
@ -1169,9 +1249,9 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
} }
Operation::Dup(line, col) => Operation::Dup(line, col) =>
{ {
if let Some(typ) = type_queue.get(0) if let Some(typ) = type_queue.first()
{ {
type_queue.push(typ.clone()); type_queue.push(*typ);
} }
else else
{ {
@ -1234,7 +1314,7 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
{ {
println!("Starting to typecheck if block"); println!("Starting to typecheck if block");
} }
let if_ret = get_return_type(if_block, &type_queue, functions, intrinsics, arrays, debug)?; let if_ret = get_return_type(if_block, type_queue, functions, intrinsics, arrays, debug)?;
let else_ret = let else_ret =
if let Some(else_block) = maybe_else_block if let Some(else_block) = maybe_else_block
{ {
@ -1242,7 +1322,7 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
{ {
println!("Starting to typecheck else block"); println!("Starting to typecheck else block");
} }
get_return_type(else_block, &type_queue, functions, intrinsics, arrays, debug)? get_return_type(else_block, type_queue, functions, intrinsics, arrays, debug)?
} }
else else
{ {
@ -1343,28 +1423,28 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
println!("{} => {:?}", debug_string, type_queue); println!("{} => {:?}", debug_string, type_queue);
} }
} }
return Ok(type_queue.clone()); Ok(type_queue.clone())
} }
fn validate_function_calls(operations: &Vec<Operation>, functions: &Vec<Function>, arrays: &Vec<Arr>, debug: bool) -> Result<(), String> fn validate_function_calls(operations: &Vec<Operation>, functions: &Vec<Function>, debug: bool) -> Result<(), String>
{ {
for function in functions for function in functions
{ {
validate_function_calls_in_block(&function.content, functions, arrays, debug)?; validate_function_calls_in_block(&function.content, functions)?;
if debug if debug
{ {
println!("Successfully validated function calls in function '{}'", function.name); println!("Successfully validated function calls in function '{}'", function.name);
} }
} }
validate_function_calls_in_block(operations, functions, arrays, debug)?; validate_function_calls_in_block(operations, functions)?;
if debug if debug
{ {
println!("Successfully validated function calls in main operations"); println!("Successfully validated function calls in main operations");
} }
return Ok(()); Ok(())
} }
fn validate_function_calls_in_block(block: &Vec<Operation>, functions: &Vec<Function>, arrays: &Vec<Arr>, debug: bool) -> Result<(), String> fn validate_function_calls_in_block(block: &Vec<Operation>, functions: &Vec<Function>) -> Result<(), String>
{ {
for operation in block for operation in block
{ {
@ -1381,22 +1461,22 @@ fn validate_function_calls_in_block(block: &Vec<Operation>, functions: &Vec<Func
} }
Operation::If(if_block, maybe_else_block, _, _) => Operation::If(if_block, maybe_else_block, _, _) =>
{ {
validate_function_calls_in_block(if_block, functions, arrays, debug)?; validate_function_calls_in_block(if_block, functions)?;
if let Some(else_block) = maybe_else_block if let Some(else_block) = maybe_else_block
{ {
validate_function_calls_in_block(else_block, functions, arrays, debug)?; validate_function_calls_in_block(else_block, functions)?;
} }
} }
Operation::While(while_block, _, _) => Operation::While(while_block, _, _) =>
{ {
validate_function_calls_in_block(while_block, functions, arrays, debug)?; validate_function_calls_in_block(while_block, functions)?;
} }
} }
} }
return Ok(()); Ok(())
} }
fn extract_arrays(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, functions: &Vec<Function>, debug: bool) -> Result<Vec<Arr>, String> fn extract_arrays(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, functions: &[Function], debug: bool) -> Result<Vec<Arr>, String>
{ {
let mut tokens_iter = tokens.iter().peekable(); let mut tokens_iter = tokens.iter().peekable();
let mut arrays: Vec<Arr> = Vec::new(); let mut arrays: Vec<Arr> = Vec::new();
@ -1489,12 +1569,16 @@ fn extract_arrays(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Datat
} }
tokens.clear(); tokens.clear();
tokens.extend_from_slice(&new_tokens); tokens.extend_from_slice(&new_tokens);
return Ok(arrays); Ok(arrays)
} }
fn sanitize_name(name: String) -> String fn sanitize_name(name: String) -> String
{ {
return name.replace("-", "_").replace("+", "_").replace("%", "percent").replace("/", "slash"); if name == "test"
{
return "test_".to_string();
}
name.replace(['-', '+'], "_").replace('%', "percent").replace('/', "slash")
} }
fn str_to_datatype(s: &str, line: i32, col: i32) -> Result<Datatype, String> fn str_to_datatype(s: &str, line: i32, col: i32) -> Result<Datatype, String>
@ -1505,7 +1589,7 @@ fn str_to_datatype(s: &str, line: i32, col: i32) -> Result<Datatype, String>
"bool" => Ok(Datatype::Bool), "bool" => Ok(Datatype::Bool),
"int" => Ok(Datatype::Int), "int" => Ok(Datatype::Int),
"str" => Ok(Datatype::String), "str" => Ok(Datatype::String),
_ => return Err(format!("Expected a datatype for the array, got {} instead at {}:{}", s, line, col)) _ => Err(format!("Expected a datatype for the array, got {} instead at {}:{}", s, line, col))
} }
} }
@ -1555,7 +1639,7 @@ fn extract_functions(tokens: &mut Vec<Token>, functions: &mut Vec<Function>, int
} }
} }
} }
None => return Err(format!("Unexpected end of file while extracting a function")) None => return Err("Unexpected end of file while extracting a function".to_string())
} }
} }
if debug if debug
@ -1608,7 +1692,7 @@ fn extract_functions(tokens: &mut Vec<Token>, functions: &mut Vec<Function>, int
} }
} }
} }
None => return Err(format!("Unexpected end of file while extracting a function")) None => return Err("Unexpected end of file while extracting a function".to_string())
} }
} }
} }
@ -1624,7 +1708,7 @@ fn extract_functions(tokens: &mut Vec<Token>, functions: &mut Vec<Function>, int
} }
tokens.clear(); tokens.clear();
tokens.extend_from_slice(&new_tokens); tokens.extend_from_slice(&new_tokens);
return Ok(()); Ok(())
} }
fn parse_block(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<Vec<Operation>, String> fn parse_block(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<Vec<Operation>, String>
@ -1638,9 +1722,9 @@ fn parse_block(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, intrinsics:
} }
else else
{ {
return Err(format!("Expected '{{' to open a block")); return Err("Expected '{' to open a block".to_string());
} }
return parse_until_delimiter(tokens_iter, intrinsics, Some("}"), debug); 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) -> Result<Vec<Operation>, String> 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>
@ -1754,7 +1838,7 @@ fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, in
{ {
if delimiter.is_some() if delimiter.is_some()
{ {
return Err(format!("Reached the end of the file while parsing a block")); return Err("Reached the end of the file while parsing a block".to_string());
} }
else else
{ {
@ -1834,7 +1918,7 @@ fn tokenize(text: &str) -> Result<Vec<Token>, String>
state = TokenizerState::Whitespace; state = TokenizerState::Whitespace;
if application_name.is_empty() if application_name.is_empty()
{ {
if let Ok(_) = word.parse::<i64>() if word.parse::<i64>().is_ok()
{ {
tokens.push(Token::IntLit(word.clone(), line, col)); tokens.push(Token::IntLit(word.clone(), line, col));
} }
@ -1862,7 +1946,7 @@ fn tokenize(text: &str) -> Result<Vec<Token>, String>
{ {
match ch match ch
{ {
'"' => return Err(format!("Having '\"' in the middle of a word is not allowed")), '"' => return Err("Having '\"' in the middle of a word is not allowed".to_string()),
'.' => '.' =>
{ {
application_name = word.clone(); application_name = word.clone();
@ -1887,7 +1971,7 @@ fn tokenize(text: &str) -> Result<Vec<Token>, String>
{ {
TokenizerState::Quote => TokenizerState::Quote =>
{ {
return Err(format!("Encountered EOF before closing string")); return Err("Encountered EOF before closing string".to_string());
} }
TokenizerState::Whitespace | TokenizerState::Comment => {}, TokenizerState::Whitespace | TokenizerState::Comment => {},
TokenizerState::Keyword => TokenizerState::Keyword =>

11
std.qbl
View File

@ -18,4 +18,13 @@ function int int => int %
function int int => int / function int int => int /
{ {
divmod req deq divmod req deq
} }
function int => int decrement
{
1 -
}
function int => int increment
{
1 +
}

View File

@ -371,4 +371,4 @@ function int int => int coordToIndex
{ {
// y x // y x
req 29 req * + req 29 req * +
} }