|
|
|
@ -3,7 +3,11 @@ use std::collections::HashMap;
|
|
|
|
|
use std::env;
|
|
|
|
|
use std::fs;
|
|
|
|
|
use std::iter::Peekable;
|
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
use std::process::Command;
|
|
|
|
|
use std::process::Stdio;
|
|
|
|
|
use std::process::exit;
|
|
|
|
|
use std::time::Instant;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
|
enum Token
|
|
|
|
@ -13,6 +17,7 @@ enum Token
|
|
|
|
|
BoolLit(String, i32, i32),
|
|
|
|
|
Keyword(String, i32, i32),
|
|
|
|
|
Apply(String, String, i32, i32),
|
|
|
|
|
Import(i32, i32),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum TokenizerState
|
|
|
|
@ -90,6 +95,7 @@ fn main()
|
|
|
|
|
("-", (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::Int]))),
|
|
|
|
|
("divmod", (Vec::from([Datatype::Int, Datatype::Int]), Vec::from([Datatype::Int, 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]))),
|
|
|
|
@ -97,7 +103,6 @@ fn main()
|
|
|
|
|
("==", (Vec::from([Datatype::Int, Datatype::Int]), Vec::from([Datatype::Bool]))),
|
|
|
|
|
("!=", (Vec::from([Datatype::Int, Datatype::Int]), Vec::from([Datatype::Bool]))),
|
|
|
|
|
("&&", (Vec::from([Datatype::Bool, Datatype::Bool]), Vec::from([Datatype::Bool]))),
|
|
|
|
|
("decrease", (Vec::from([Datatype::Int]), Vec::from([Datatype::Int]))),
|
|
|
|
|
]);
|
|
|
|
|
let args: Vec<String> = env::args().collect();
|
|
|
|
|
if args.len() < 2
|
|
|
|
@ -106,12 +111,14 @@ fn main()
|
|
|
|
|
}
|
|
|
|
|
let mut debug = false;
|
|
|
|
|
let mut interpret = false;
|
|
|
|
|
let mut run = false;
|
|
|
|
|
for arg in &args[3..]
|
|
|
|
|
{
|
|
|
|
|
match arg.as_str()
|
|
|
|
|
{
|
|
|
|
|
"-d" | "--debug" => debug = true,
|
|
|
|
|
"-i" | "--interpret" => interpret = true,
|
|
|
|
|
"-r" | "--run" => run = true,
|
|
|
|
|
_ => panic!("Unknown option {}", arg),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -125,7 +132,7 @@ fn main()
|
|
|
|
|
let f = f.unwrap();
|
|
|
|
|
let file_content = fs::read_to_string(f.path()).unwrap().replace("\r\n", "\n");
|
|
|
|
|
println!("========NOW TESTING {:?}========", f.path());
|
|
|
|
|
match compile(&file_content, &intrinsics, interpret, debug)
|
|
|
|
|
match compile(&file_content, f.path().to_str().unwrap(), &intrinsics, interpret, run, debug)
|
|
|
|
|
{
|
|
|
|
|
Ok(maybe_msg) =>
|
|
|
|
|
{
|
|
|
|
@ -134,7 +141,7 @@ fn main()
|
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
println!("===PASSED===");
|
|
|
|
@ -153,7 +160,7 @@ fn main()
|
|
|
|
|
Err(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===");
|
|
|
|
|
count += 1;
|
|
|
|
@ -162,8 +169,9 @@ fn main()
|
|
|
|
|
{
|
|
|
|
|
if let Some(index) = file_content.find(":END:")
|
|
|
|
|
{
|
|
|
|
|
let expected = &format!("//invalid,{}:END:", msg.replace('\n', "\n//"));
|
|
|
|
|
let expected_output = file_content[10..index].replace("\n//", "\n");
|
|
|
|
|
println!("\n\n===FAILED===\nExpected the output to be {}", expected_output);
|
|
|
|
|
println!("\n===FAILED===\nExpected the output to be\n'{}'\n({})", expected_output, expected);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@ -182,7 +190,7 @@ fn main()
|
|
|
|
|
"-c" | "--compile" =>
|
|
|
|
|
{
|
|
|
|
|
let file_content = fs::read_to_string(&args[2]).expect("Could not read the source file");
|
|
|
|
|
match compile(&file_content, &intrinsics, interpret, debug)
|
|
|
|
|
match compile(&file_content, &args[2], &intrinsics, interpret, run, debug)
|
|
|
|
|
{
|
|
|
|
|
Ok(maybe_msg) =>
|
|
|
|
|
{
|
|
|
|
@ -198,24 +206,28 @@ fn main()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn compile(file_content: &String, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, interpret: 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());
|
|
|
|
|
let functions: Vec<Function> = extract_functions(&mut tokens, &intrinsics, debug)?;
|
|
|
|
|
let mut functions: Vec<Function> = Vec::new();
|
|
|
|
|
extract_functions(&mut tokens, &mut functions, intrinsics, debug)?;
|
|
|
|
|
println!("---Done extracting functions, got {} functions and reduced the token count to {}---", functions.len(), tokens.len());
|
|
|
|
|
let mut arrays: Vec<Arr> = extract_arrays(&mut tokens, &intrinsics, &functions, debug)?;
|
|
|
|
|
resolve_imports(&mut tokens, &mut functions, file_path, &mut Vec::from([fs::canonicalize(file_path).unwrap()]), intrinsics, debug)?;
|
|
|
|
|
println!("---Done importing files---");
|
|
|
|
|
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());
|
|
|
|
|
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());
|
|
|
|
|
validate_function_calls(&operations, &functions, &arrays, debug)?;
|
|
|
|
|
validate_function_calls(&operations, &functions, debug)?;
|
|
|
|
|
println!("---Done validating function calls---");
|
|
|
|
|
typecheck(&operations, &functions, &intrinsics, &arrays, debug)?;
|
|
|
|
|
typecheck(&operations, &functions, intrinsics, &arrays, debug)?;
|
|
|
|
|
println!("---Done typechecking---");
|
|
|
|
|
let start = Instant::now();
|
|
|
|
|
let output = if interpret
|
|
|
|
|
{
|
|
|
|
|
println!("---Starting to interpret the program---");
|
|
|
|
|
Some(interpret_program(&operations, &mut Vec::new(), &functions, &mut arrays, &intrinsics, debug)?)
|
|
|
|
|
Some(interpret_program(&operations, &mut Vec::new(), &functions, &mut arrays, debug)?)
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@ -223,13 +235,113 @@ fn compile(file_content: &String, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec
|
|
|
|
|
};
|
|
|
|
|
if !interpret
|
|
|
|
|
{
|
|
|
|
|
match generate_assembly_linux_x64(&operations, &functions, &intrinsics, &arrays, debug)
|
|
|
|
|
if let Err(err) = generate_assembly_linux_x64(&operations, &functions, &arrays)
|
|
|
|
|
{
|
|
|
|
|
Ok(()) => return Ok(None),
|
|
|
|
|
Err(error) => return Err(error.to_string()),
|
|
|
|
|
return Err(err.to_string());
|
|
|
|
|
}
|
|
|
|
|
let mut fasm_process = match Command::new("fasm").arg("out.asm").spawn()
|
|
|
|
|
{
|
|
|
|
|
Ok(process) => process,
|
|
|
|
|
Err(err) => return Err(format!("Fasm process error: {}", err)),
|
|
|
|
|
};
|
|
|
|
|
match fasm_process.wait()
|
|
|
|
|
{
|
|
|
|
|
Ok(status) =>
|
|
|
|
|
{
|
|
|
|
|
if !status.success()
|
|
|
|
|
{
|
|
|
|
|
return Err(format!("fasm exited with an error: {}", status));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Err(err) => return Err(err.to_string()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Ok(output);
|
|
|
|
|
if run
|
|
|
|
|
{
|
|
|
|
|
let process = match Command::new("./out").stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()
|
|
|
|
|
{
|
|
|
|
|
Ok(process) => process,
|
|
|
|
|
Err(err) => return Err(err.to_string()),
|
|
|
|
|
};
|
|
|
|
|
return match process.wait_with_output()
|
|
|
|
|
{
|
|
|
|
|
Ok(output) =>
|
|
|
|
|
{
|
|
|
|
|
match String::from_utf8(output.stdout)
|
|
|
|
|
{
|
|
|
|
|
Ok(stdout) =>
|
|
|
|
|
{
|
|
|
|
|
match String::from_utf8(output.stderr)
|
|
|
|
|
{
|
|
|
|
|
Ok(stderr) =>
|
|
|
|
|
{
|
|
|
|
|
let text = format!("{}{}", stdout, stderr);
|
|
|
|
|
match output.status.code()
|
|
|
|
|
{
|
|
|
|
|
Some(0) => Ok(Some(text)),
|
|
|
|
|
_ => Err(text),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Err(err) => Err(err.to_string()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Err(err) => Err(err.to_string()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Err(err) => Err(err.to_string()),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
println!("---Done after {:?}---", start.elapsed());
|
|
|
|
|
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>
|
|
|
|
|
{
|
|
|
|
|
let mut tokens_iter = tokens.iter();
|
|
|
|
|
let mut new_tokens: Vec<Token> = Vec::new();
|
|
|
|
|
while let Some(token) = tokens_iter.next()
|
|
|
|
|
{
|
|
|
|
|
if let Token::Import(line, col) = token
|
|
|
|
|
{
|
|
|
|
|
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);
|
|
|
|
|
if visited_paths.contains(&full_import_path)
|
|
|
|
|
{
|
|
|
|
|
println!("--Already visited {}--", full_import_path.display());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
visited_paths.push(full_import_path.clone());
|
|
|
|
|
let maybe_file_content = fs::read_to_string(full_import_path);
|
|
|
|
|
match maybe_file_content
|
|
|
|
|
{
|
|
|
|
|
Ok(file_content) =>
|
|
|
|
|
{
|
|
|
|
|
let mut import_tokens: Vec<Token> = tokenize(&file_content)?;
|
|
|
|
|
println!("--Done tokenizing the imported file at {}:{}, got {} tokens--", line, col, tokens.len());
|
|
|
|
|
extract_functions(&mut import_tokens, functions, intrinsics, debug)?;
|
|
|
|
|
resolve_imports(&mut import_tokens, functions, file_path, visited_paths, intrinsics, debug)?;
|
|
|
|
|
println!("--Now totalling {} functions--", functions.len());
|
|
|
|
|
}
|
|
|
|
|
Err(e) => return Err(e.to_string()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return Err(format!("Expected an import location at {}:{}", line, col));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
new_tokens.push(token.clone());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
tokens.clear();
|
|
|
|
|
tokens.extend_from_slice(&new_tokens);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct AssemblyData
|
|
|
|
@ -246,13 +358,18 @@ fn merge_assemblies(data: &mut AssemblyData, data2: AssemblyData)
|
|
|
|
|
data.strings += data2.strings.as_str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ASSEMBLY_LINUX_X64_QUEUE_LENGTH: u32 = 1024;
|
|
|
|
|
const ASSEMBLY_LINUX_X64_QUEUE_LENGTH: u32 = 8192;
|
|
|
|
|
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_EXIT: &str = "\tmov rax, 60\n\tmov rdi, 0\n\tsyscall\n";
|
|
|
|
|
const ASSEMBLY_LINUX_X64_DYNAMIC_DATA_LENGTH: u32 = 16384;
|
|
|
|
|
|
|
|
|
|
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>
|
|
|
|
|
// r12: head
|
|
|
|
|
// r13: tail
|
|
|
|
|
// r14: base
|
|
|
|
|
// r15: dynamic end
|
|
|
|
|
|
|
|
|
|
fn generate_assembly_linux_x64(operations: &Vec<Operation>, functions: &Vec<Function>, arrays: &Vec<Arr>) -> Result<(), std::io::Error>
|
|
|
|
|
{
|
|
|
|
|
let mut data = AssemblyData
|
|
|
|
|
{
|
|
|
|
@ -265,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.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;
|
|
|
|
|
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")
|
|
|
|
@ -304,16 +421,62 @@ fn generate_assembly_linux_x64(operations: &Vec<Operation>, functions: &Vec<Func
|
|
|
|
|
data.code += "\tlea rax, [dynamic+rsi]\n";
|
|
|
|
|
data.code += "\tret\n";
|
|
|
|
|
}
|
|
|
|
|
if data.code.contains("exception_array_read_out_of_bounds")
|
|
|
|
|
{
|
|
|
|
|
data.strings += "\texception_array_oob_msg db \"Attempted array out-of-bounds access\", 10\n";
|
|
|
|
|
data.code += "exception_array_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_array_oob_msg\n";
|
|
|
|
|
data.code += "\tsyscall\n";
|
|
|
|
|
data.code += "\tmov rax, 60\n";
|
|
|
|
|
data.code += "\tmov rdi, -1\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))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// r12: head
|
|
|
|
|
// r13: tail
|
|
|
|
|
// r14: base
|
|
|
|
|
// r15: dynamic end
|
|
|
|
|
fn generate_assembly_linux_x64_array_oob_check(length: i64) -> String
|
|
|
|
|
{
|
|
|
|
|
let mut data = String::new();
|
|
|
|
|
data += "\t\t;;Array bounds check\n";
|
|
|
|
|
data += format!("\tcmp qword rax, {}\n", length).as_str();
|
|
|
|
|
data += "\tjge exception_array_read_out_of_bounds\n";
|
|
|
|
|
data += "\tcmp qword rax, 0\n";
|
|
|
|
|
data += "\tjl exception_array_read_out_of_bounds\n";
|
|
|
|
|
data += "\t\t;;Array bounds check over\n";
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
@ -338,7 +501,15 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
{
|
|
|
|
|
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 =>
|
|
|
|
|
{
|
|
|
|
@ -346,24 +517,55 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
}
|
|
|
|
|
Datatype::String =>
|
|
|
|
|
{
|
|
|
|
|
data.strings += format!("\tstr_{}_{}: dq {}, \"{}\", 0\n", line, col, value.len(), value).as_str();
|
|
|
|
|
data.strings += format!("\tstr_{}_{}: db {}, {}, {}, {}, {}, {}, {}, {}, \"{}\", 0\n",
|
|
|
|
|
line, col,
|
|
|
|
|
value.len() % 256,
|
|
|
|
|
(value.len() >> 8) % 256,
|
|
|
|
|
(value.len() >> 16) % 256,
|
|
|
|
|
(value.len() >> 24) % 256,
|
|
|
|
|
(value.len() >> 32) % 256,
|
|
|
|
|
(value.len() >> 40) % 256,
|
|
|
|
|
(value.len() >> 48) % 256,
|
|
|
|
|
(value.len() >> 56) % 256,
|
|
|
|
|
value).as_str();
|
|
|
|
|
data.code += format!("\tlea rax, [str_{}_{}]\n", line, col).as_str();
|
|
|
|
|
data.code += "\tmov [queue+8*r13], rax\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
Operation::Requeue(line, col) =>
|
|
|
|
|
{
|
|
|
|
|
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 [queue+8*r13], rax\n";
|
|
|
|
|
data.code += "\tinc r12\n";
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += "\tmov [queue+8*r13], rax\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) =>
|
|
|
|
|
{
|
|
|
|
|
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 rbx, [queue+8*r12+8]\n";
|
|
|
|
|
data.code += "\tadd r12, 2\n";
|
|
|
|
@ -371,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+8], rax\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) =>
|
|
|
|
|
{
|
|
|
|
@ -380,13 +593,12 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
data.code += format!("while_{}_{}:\n", line, col).as_str();
|
|
|
|
|
data.code += "\tinc r12\n";
|
|
|
|
|
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 += format!("\tjne while_{}_{}\n", line, col).as_str();
|
|
|
|
|
data.code += format!("while_{}_{}_end:\n", line, col).as_str();
|
|
|
|
|
data.code += "\tinc r12\n";
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
Operation::If(if_operations, maybe_else_operations, line, col) =>
|
|
|
|
|
{
|
|
|
|
@ -395,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 += "\tinc r12\n";
|
|
|
|
|
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!("else_{}_{}:\n", line, col).as_str();
|
|
|
|
|
data.code += "\tinc r12\n";
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
@ -412,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 [queue+8*r13], rax\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
Operation::Intrinsic(name, line, col) =>
|
|
|
|
|
{
|
|
|
|
@ -430,7 +643,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
// data
|
|
|
|
|
data.code += "\tlea rsi, [rsi+8]\n";
|
|
|
|
|
// incorporate the null byte
|
|
|
|
|
data.code += "\tinc rdx\n";
|
|
|
|
|
//data.code += "\tinc rdx\n";
|
|
|
|
|
data.code += "\tsyscall\n";
|
|
|
|
|
// TODO: factor this out
|
|
|
|
|
data.code += "\tinc r12\n";
|
|
|
|
@ -448,7 +661,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
// data
|
|
|
|
|
data.code += "\tlea rsi, [rsi+8]\n";
|
|
|
|
|
// incorporate the null byte
|
|
|
|
|
data.code += "\tinc rdx\n";
|
|
|
|
|
//data.code += "\tinc rdx\n";
|
|
|
|
|
data.code += "\tsyscall\n";
|
|
|
|
|
// TODO: factor this out
|
|
|
|
|
data.code += "\tinc r12\n";
|
|
|
|
@ -467,6 +680,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
data.code += "\tcall intToStr\n";
|
|
|
|
|
data.code += "\tmov [queue+8*r13], rax\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
"-" =>
|
|
|
|
|
{
|
|
|
|
@ -478,6 +692,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
data.code += "\tsub rax, rbx\n";
|
|
|
|
|
data.code += "\tmov [queue+8*r13], rax\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
"+" =>
|
|
|
|
|
{
|
|
|
|
@ -489,6 +704,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
data.code += "\tadd rax, rbx\n";
|
|
|
|
|
data.code += "\tmov [queue+8*r13], rax\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
"*" =>
|
|
|
|
|
{
|
|
|
|
@ -500,6 +716,23 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
data.code += "\tmul rbx\n";
|
|
|
|
|
data.code += "\tmov [queue+8*r13], rax\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
"divmod" =>
|
|
|
|
|
{
|
|
|
|
|
data.code += "\tmov qword rax, [queue+8*r12]\n";
|
|
|
|
|
data.code += "\tmov qword rdx, 0\n";
|
|
|
|
|
data.code += "\tinc r12\n";
|
|
|
|
|
data.code += "\tmov qword rbx, [queue+8*r12]\n";
|
|
|
|
|
data.code += "\tinc r12\n";
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += "\tidiv rbx\n";
|
|
|
|
|
data.code += "\tmov [queue+8*r13], rax\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 += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
">" =>
|
|
|
|
|
{
|
|
|
|
@ -512,6 +745,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += "\tmov qword [queue+8*r13], rbx\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
"<" =>
|
|
|
|
|
{
|
|
|
|
@ -524,6 +758,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += "\tmov qword [queue+8*r13], rbx\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
">=" =>
|
|
|
|
|
{
|
|
|
|
@ -536,6 +771,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += "\tmov qword [queue+8*r13], rbx\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
"<=" =>
|
|
|
|
|
{
|
|
|
|
@ -548,6 +784,7 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += "\tmov qword [queue+8*r13], rbx\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
"==" =>
|
|
|
|
|
{
|
|
|
|
@ -560,6 +797,20 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += "\tmov qword [queue+8*r13], rbx\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
"!=" =>
|
|
|
|
|
{
|
|
|
|
|
data.code += "\tmov rbx, 0\n";
|
|
|
|
|
data.code += "\tmov rcx, 1\n";
|
|
|
|
|
data.code += "\tmov rax, [queue+8*r12]\n";
|
|
|
|
|
data.code += "\tcmp qword rax, [queue+8*r12+8]\n";
|
|
|
|
|
data.code += "\tcmovne rbx, rcx\n";
|
|
|
|
|
data.code += "\tadd r12, 2\n";
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += "\tmov qword [queue+8*r13], rbx\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
"&&" =>
|
|
|
|
|
{
|
|
|
|
@ -570,27 +821,32 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += "\tmov [queue+8*r13], rax\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
_ => todo!("intrinsic {} {}:{}", name, line, col)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Operation::Apply(name, word, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
let array = arrays.iter().find(|x| &x.name == name).unwrap();
|
|
|
|
|
data.code += format!("\t;;apply {}.{} {}:{}\n", name, word, line, col).as_str();
|
|
|
|
|
match word.as_str()
|
|
|
|
|
{
|
|
|
|
|
"read" =>
|
|
|
|
|
{
|
|
|
|
|
data.code += "\tmov rax, [queue+8*r12]\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_array_oob_check(array.length).as_str();
|
|
|
|
|
data.code += "\tinc r12\n";
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += format!("\tmov qword rbx, [arr_{}+8*rax]\n", name).as_str();
|
|
|
|
|
data.code += "\tmov qword [queue+8*r13], rbx\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
"write" =>
|
|
|
|
|
{
|
|
|
|
|
data.code += "\tmov rax, [queue+8*r12]\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_array_oob_check(array.length).as_str();
|
|
|
|
|
data.code += "\tinc r12\n";
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += "\tmov qword rbx, [queue+8*r12]\n";
|
|
|
|
@ -600,9 +856,9 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
}
|
|
|
|
|
"length" =>
|
|
|
|
|
{
|
|
|
|
|
let array = arrays.iter().find(|x| &x.name == name).unwrap();
|
|
|
|
|
data.code += format!("\tmov qword [queue+8*r13], {}\n", array.length).as_str();
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
_ => todo!("apply {}", word)
|
|
|
|
|
}
|
|
|
|
@ -614,9 +870,11 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
for _ in 0..function.ins.len()
|
|
|
|
|
{
|
|
|
|
|
data.code += "\tmov rax, [queue+8*r12]\n";
|
|
|
|
|
data.code += "\tmov [queue+8*r13], rax\n";
|
|
|
|
|
data.code += "\tinc r12\n";
|
|
|
|
|
data.code += ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE;
|
|
|
|
|
data.code += "\tmov [queue+8*r13], rax\n";
|
|
|
|
|
data.code += "\tinc r13\n";
|
|
|
|
|
data.code += generate_assembly_linux_x64_queue_oob_check().as_str();
|
|
|
|
|
}
|
|
|
|
|
data.code += "\t;; move pointers\n";
|
|
|
|
|
// save the current base
|
|
|
|
@ -654,10 +912,10 @@ fn generate_assembly_linux_x64_block(operations: &Vec<Operation>, functions: &Ve
|
|
|
|
|
_ => 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
|
|
|
|
|
{
|
|
|
|
@ -665,12 +923,12 @@ fn generate_assembly_linux_x64_function(name: &str, operations: &Vec<Operation>,
|
|
|
|
|
code: format!("{}:\n", name),
|
|
|
|
|
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";
|
|
|
|
|
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();
|
|
|
|
|
for operation in operations
|
|
|
|
@ -696,7 +954,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
}
|
|
|
|
|
Operation::Dup(_, _) =>
|
|
|
|
|
{
|
|
|
|
|
let val = queue.get(0).unwrap();
|
|
|
|
|
let val = queue.first().unwrap();
|
|
|
|
|
queue.push(val.clone());
|
|
|
|
|
}
|
|
|
|
|
Operation::Swap(_, _) =>
|
|
|
|
@ -715,7 +973,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
let val = queue.remove(0);
|
|
|
|
|
function_context.push(val);
|
|
|
|
|
}
|
|
|
|
|
output += interpret_program(&function.content, function_context, functions, arrays, intrinsics, debug)?.as_str();
|
|
|
|
|
output += interpret_program(&function.content, function_context, functions, arrays, debug)?.as_str();
|
|
|
|
|
for val in function_context
|
|
|
|
|
{
|
|
|
|
|
queue.push(val.to_string());
|
|
|
|
@ -726,11 +984,11 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
let val = queue.remove(0);
|
|
|
|
|
if val == "true"
|
|
|
|
|
{
|
|
|
|
|
output += interpret_program(if_block, queue, functions, arrays, intrinsics, debug)?.as_str();
|
|
|
|
|
output += interpret_program(if_block, queue, functions, arrays, debug)?.as_str();
|
|
|
|
|
}
|
|
|
|
|
else if let Some(else_block) = maybe_else_block
|
|
|
|
|
{
|
|
|
|
|
output += interpret_program(else_block, queue, functions, arrays, intrinsics, debug)?.as_str();
|
|
|
|
|
output += interpret_program(else_block, queue, functions, arrays, debug)?.as_str();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Operation::Intrinsic(intrinsic_name, line, col) =>
|
|
|
|
@ -739,7 +997,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
{
|
|
|
|
|
"print" =>
|
|
|
|
|
{
|
|
|
|
|
output += format!("{}", queue.remove(0)).as_str();
|
|
|
|
|
output += queue.remove(0).to_string().as_str();
|
|
|
|
|
}
|
|
|
|
|
"-" =>
|
|
|
|
|
{
|
|
|
|
@ -759,6 +1017,13 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
let multiplicant2 = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
queue.push((multiplicant1 * multiplicant2).to_string());
|
|
|
|
|
}
|
|
|
|
|
"divmod" =>
|
|
|
|
|
{
|
|
|
|
|
let dividend = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
let divisor = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
queue.push((dividend / divisor).to_string());
|
|
|
|
|
queue.push((dividend % divisor).to_string());
|
|
|
|
|
}
|
|
|
|
|
">" =>
|
|
|
|
|
{
|
|
|
|
|
let first = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
@ -801,11 +1066,6 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
let second = queue.remove(0).parse::<bool>().unwrap();
|
|
|
|
|
queue.push((first && second).to_string());
|
|
|
|
|
}
|
|
|
|
|
"decrease" =>
|
|
|
|
|
{
|
|
|
|
|
let val = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
queue.push((val - 1).to_string());
|
|
|
|
|
}
|
|
|
|
|
"println" =>
|
|
|
|
|
{
|
|
|
|
|
output += format!("{}\n", queue.remove(0)).as_str();
|
|
|
|
@ -831,11 +1091,13 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
let position: i64 = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
if position >= arr.length
|
|
|
|
|
{
|
|
|
|
|
return Err(format!("Attempted an out of bounds write for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col));
|
|
|
|
|
//return Err(format!("Attempted an out of bounds write for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col));
|
|
|
|
|
return Err(String::from("Attempted array out-of-bounds access\n"));
|
|
|
|
|
}
|
|
|
|
|
if position < 0
|
|
|
|
|
{
|
|
|
|
|
return Err(format!("Attempted an out of bounds write for array {} ({} < 0) at {}:{}", arr.name, position, line, col));
|
|
|
|
|
//return Err(format!("Attempted an out of bounds write for array {} ({} < 0) at {}:{}", arr.name, position, line, col));
|
|
|
|
|
return Err(String::from("Attempted array out-of-bounds access\n"));
|
|
|
|
|
}
|
|
|
|
|
let data = queue.remove(0);
|
|
|
|
|
if debug
|
|
|
|
@ -853,11 +1115,13 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
let position: i64 = queue.remove(0).parse::<i64>().unwrap();
|
|
|
|
|
if position >= arr.length
|
|
|
|
|
{
|
|
|
|
|
return Err(format!("Attempted an out of bounds read for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col));
|
|
|
|
|
//return Err(format!("Attempted an out of bounds read for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col));
|
|
|
|
|
return Err(String::from("Attempted array out-of-bounds access\n"));
|
|
|
|
|
}
|
|
|
|
|
if position < 0
|
|
|
|
|
{
|
|
|
|
|
return Err(format!("Attempted an out of bounds read for array {} ({} < 0) at {}:{}", arr.name, position, line, col));
|
|
|
|
|
//return Err(format!("Attempted an out of bounds read for array {} ({} < 0) at {}:{}", arr.name, position, line, col));
|
|
|
|
|
return Err(String::from("Attempted array out-of-bounds access\n"));
|
|
|
|
|
}
|
|
|
|
|
queue.push(arr.data[position as usize].clone());
|
|
|
|
|
}
|
|
|
|
@ -877,7 +1141,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
output += interpret_program(while_block, queue, functions, arrays, intrinsics, debug)?.as_str();
|
|
|
|
|
output += interpret_program(while_block, queue, functions, arrays, debug)?.as_str();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Operation::Depth(_, _) =>
|
|
|
|
@ -896,7 +1160,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|
|
|
|
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>
|
|
|
|
@ -922,10 +1186,10 @@ fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics:
|
|
|
|
|
{
|
|
|
|
|
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)?;
|
|
|
|
|
if &actual_outs != outs
|
|
|
|
@ -955,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 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();
|
|
|
|
|
type_queue.extend_from_slice(ins);
|
|
|
|
@ -985,9 +1249,9 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
@ -1050,7 +1314,7 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
{
|
|
|
|
|
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 =
|
|
|
|
|
if let Some(else_block) = maybe_else_block
|
|
|
|
|
{
|
|
|
|
@ -1058,7 +1322,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, arrays, debug)?
|
|
|
|
|
get_return_type(else_block, type_queue, functions, intrinsics, arrays, debug)?
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
@ -1159,28 +1423,28 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
validate_function_calls_in_block(&function.content, functions, arrays, debug)?;
|
|
|
|
|
validate_function_calls_in_block(&function.content, functions)?;
|
|
|
|
|
if debug
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
@ -1197,22 +1461,22 @@ fn validate_function_calls_in_block(block: &Vec<Operation>, functions: &Vec<Func
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
validate_function_calls_in_block(else_block, functions, arrays, debug)?;
|
|
|
|
|
validate_function_calls_in_block(else_block, functions)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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 arrays: Vec<Arr> = Vec::new();
|
|
|
|
@ -1305,12 +1569,16 @@ fn extract_arrays(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Datat
|
|
|
|
|
}
|
|
|
|
|
tokens.clear();
|
|
|
|
|
tokens.extend_from_slice(&new_tokens);
|
|
|
|
|
return Ok(arrays);
|
|
|
|
|
Ok(arrays)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn sanitize_name(name: String) -> String
|
|
|
|
|
{
|
|
|
|
|
return name.replace("-", "_").replace("+", "_");
|
|
|
|
|
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>
|
|
|
|
@ -1321,14 +1589,13 @@ fn str_to_datatype(s: &str, line: i32, col: i32) -> Result<Datatype, String>
|
|
|
|
|
"bool" => Ok(Datatype::Bool),
|
|
|
|
|
"int" => Ok(Datatype::Int),
|
|
|
|
|
"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))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<Vec<Function>, String>
|
|
|
|
|
fn extract_functions(tokens: &mut Vec<Token>, functions: &mut Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<(), String>
|
|
|
|
|
{
|
|
|
|
|
let mut tokens_iter = tokens.iter().peekable();
|
|
|
|
|
let mut functions: Vec<Function> = Vec::new();
|
|
|
|
|
let mut new_tokens: Vec<Token> = Vec::new();
|
|
|
|
|
while let Some(token) = tokens_iter.next()
|
|
|
|
|
{
|
|
|
|
@ -1350,7 +1617,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) | Token::BoolLit(_, line, col) | Token::Import(line, col) |
|
|
|
|
|
Token::Apply(_, _, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
return Err(format!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col));
|
|
|
|
@ -1372,7 +1639,7 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
@ -1389,7 +1656,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) | Token::BoolLit(_, line, col) | Token::Import(line, col) |
|
|
|
|
|
Token::Apply(_, _, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
return Err(format!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col));
|
|
|
|
@ -1402,7 +1669,7 @@ 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" | "???" => return Err(format!("Expected function name but got {} at {}:{}", word, line, col)),
|
|
|
|
|
"{" | "}" | "deq" | "req" | "dup" | "swp" | "true" | "false" | "depth" | "???" | "import" => return Err(format!("Expected function name but got {} at {}:{}", word, line, col)),
|
|
|
|
|
_ =>
|
|
|
|
|
{
|
|
|
|
|
if functions.iter().any(|x| &x.name == word)
|
|
|
|
@ -1425,7 +1692,7 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1441,7 +1708,7 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|
|
|
|
}
|
|
|
|
|
tokens.clear();
|
|
|
|
|
tokens.extend_from_slice(&new_tokens);
|
|
|
|
|
return Ok(functions);
|
|
|
|
|
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>
|
|
|
|
@ -1455,9 +1722,9 @@ fn parse_block(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, intrinsics:
|
|
|
|
|
}
|
|
|
|
|
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>
|
|
|
|
@ -1488,6 +1755,10 @@ fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, in
|
|
|
|
|
{
|
|
|
|
|
operations.push(Operation::Apply(sanitize_name(name.clone()), word.clone(), *line, *col));
|
|
|
|
|
}
|
|
|
|
|
Token::Import(line, col) =>
|
|
|
|
|
{
|
|
|
|
|
return Err(format!("Unexpected import token at {}:{}, should have been resolved before, probably a compiler bug", line, col));
|
|
|
|
|
}
|
|
|
|
|
Token::Keyword(word, line, col) =>
|
|
|
|
|
{
|
|
|
|
|
if intrinsics.contains_key(word.as_str())
|
|
|
|
@ -1567,7 +1838,7 @@ fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, in
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
@ -1647,7 +1918,7 @@ fn tokenize(text: &str) -> Result<Vec<Token>, String>
|
|
|
|
|
state = TokenizerState::Whitespace;
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
@ -1655,6 +1926,10 @@ fn tokenize(text: &str) -> Result<Vec<Token>, String>
|
|
|
|
|
{
|
|
|
|
|
tokens.push(Token::BoolLit(word.clone(), line, col));
|
|
|
|
|
}
|
|
|
|
|
else if word == "import"
|
|
|
|
|
{
|
|
|
|
|
tokens.push(Token::Import(line, col));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tokens.push(Token::Keyword(word.clone(), line, col));
|
|
|
|
@ -1671,7 +1946,7 @@ fn tokenize(text: &str) -> Result<Vec<Token>, String>
|
|
|
|
|
{
|
|
|
|
|
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();
|
|
|
|
@ -1696,7 +1971,7 @@ fn tokenize(text: &str) -> Result<Vec<Token>, String>
|
|
|
|
|
{
|
|
|
|
|
TokenizerState::Quote =>
|
|
|
|
|
{
|
|
|
|
|
return Err(format!("Encountered EOF before closing string"));
|
|
|
|
|
return Err("Encountered EOF before closing string".to_string());
|
|
|
|
|
}
|
|
|
|
|
TokenizerState::Whitespace | TokenizerState::Comment => {},
|
|
|
|
|
TokenizerState::Keyword =>
|
|
|
|
|