Add arrays, making the language turing complete
See tests/rule110.qbl for turing completeness
This commit is contained in:
parent
2255aaff8b
commit
e4a7bcccc0
296
src/main.rs
296
src/main.rs
@ -12,6 +12,7 @@ enum Token
|
|||||||
IntLit(String, i32, i32),
|
IntLit(String, i32, i32),
|
||||||
BoolLit(String, i32, i32),
|
BoolLit(String, i32, i32),
|
||||||
Keyword(String, i32, i32),
|
Keyword(String, i32, i32),
|
||||||
|
Apply(String, String, i32, i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TokenizerState
|
enum TokenizerState
|
||||||
@ -51,6 +52,15 @@ struct Function
|
|||||||
content: Vec<Operation>,
|
content: Vec<Operation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Arr
|
||||||
|
{
|
||||||
|
name: String,
|
||||||
|
datatype: Datatype,
|
||||||
|
length: i64,
|
||||||
|
data: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Operation
|
enum Operation
|
||||||
{
|
{
|
||||||
@ -64,6 +74,7 @@ enum Operation
|
|||||||
FunctionCall(String, i32, i32),
|
FunctionCall(String, i32, i32),
|
||||||
If(Vec<Operation>, Option<Vec<Operation>>, i32, i32),
|
If(Vec<Operation>, Option<Vec<Operation>>, i32, i32),
|
||||||
While(Vec<Operation>, i32, i32),
|
While(Vec<Operation>, i32, i32),
|
||||||
|
Apply(String, String, i32, i32),
|
||||||
Depth(i32, i32),
|
Depth(i32, i32),
|
||||||
QueueDiagnostic(i32, i32),
|
QueueDiagnostic(i32, i32),
|
||||||
}
|
}
|
||||||
@ -123,7 +134,7 @@ fn main()
|
|||||||
println!("===PASSED===");
|
println!("===PASSED===");
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
else if let Some(index) = file_content.find("//:END:")
|
else if let Some(index) = file_content.find(":END:")
|
||||||
{
|
{
|
||||||
let expected_output = file_content[8..index].replace("\n//", "\n");
|
let expected_output = file_content[8..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);
|
||||||
@ -141,14 +152,21 @@ fn main()
|
|||||||
println!("===PASSED===");
|
println!("===PASSED===");
|
||||||
count += 1;
|
count += 1;
|
||||||
}
|
}
|
||||||
else if let Some(index) = file_content.find("//:END:")
|
else if file_content.starts_with("//invalid,")
|
||||||
{
|
{
|
||||||
let expected_output = file_content[10..index].replace("\n//", "\n");
|
if let Some(index) = file_content.find(":END:")
|
||||||
println!("\n\n===FAILED===\nExpected the output to be {}", expected_output);
|
{
|
||||||
|
let expected_output = file_content[10..index].replace("\n//", "\n");
|
||||||
|
println!("\n\n===FAILED===\nExpected the output to be {}", expected_output);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
panic!("Could not find an ending marker (:END:) for the expected output in {:?}", f.file_name());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
panic!("Could not find an ending marker (:END:) for the expected output in {:?}", f.file_name());
|
println!("Unexpected error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,16 +199,18 @@ fn compile(file_content: &String, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec
|
|||||||
println!("---Done tokenizing, got {} tokens---", tokens.len());
|
println!("---Done tokenizing, got {} tokens---", tokens.len());
|
||||||
let functions: Vec<Function> = extract_functions(&mut tokens, &intrinsics, debug)?;
|
let functions: Vec<Function> = extract_functions(&mut tokens, &intrinsics, debug)?;
|
||||||
println!("---Done extracting functions, got {} functions and reduced the token count to {}---", functions.len(), tokens.len());
|
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)?;
|
||||||
|
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, debug)?;
|
validate_function_calls(&operations, &functions, &arrays, debug)?;
|
||||||
println!("---Done validating function calls---");
|
println!("---Done validating function calls---");
|
||||||
typecheck(&operations, &functions, &intrinsics, debug)?;
|
typecheck(&operations, &functions, &intrinsics, &arrays, debug)?;
|
||||||
println!("---Done typechecking---");
|
println!("---Done typechecking---");
|
||||||
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, &intrinsics, debug))
|
Some(interpret_program(&operations, &mut Vec::new(), &functions, &mut arrays, &intrinsics, debug))
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -199,7 +219,7 @@ fn compile(file_content: &String, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec
|
|||||||
return Ok(output);
|
return Ok(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> String
|
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) -> String
|
||||||
{
|
{
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
for operation in operations
|
for operation in operations
|
||||||
@ -244,7 +264,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, intrinsics, debug).as_str();
|
output += interpret_program(&function.content, function_context, functions, arrays, intrinsics, debug).as_str();
|
||||||
for val in function_context
|
for val in function_context
|
||||||
{
|
{
|
||||||
queue.push(val.to_string());
|
queue.push(val.to_string());
|
||||||
@ -255,11 +275,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, intrinsics, debug).as_str();
|
output += interpret_program(if_block, queue, functions, arrays, intrinsics, 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, intrinsics, debug).as_str();
|
output += interpret_program(else_block, queue, functions, arrays, intrinsics, debug).as_str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::Intrinsic(intrinsic_name, line, col) =>
|
Operation::Intrinsic(intrinsic_name, line, col) =>
|
||||||
@ -321,6 +341,36 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Operation::Apply(name, word, line, col) =>
|
||||||
|
{
|
||||||
|
let arr: &mut Arr = arrays.iter_mut().find(|x| &x.name == name).unwrap();
|
||||||
|
match word.as_str()
|
||||||
|
{
|
||||||
|
"write" =>
|
||||||
|
{
|
||||||
|
let position: i64 = queue.remove(0).parse::<i64>().unwrap();
|
||||||
|
if position >= arr.length
|
||||||
|
{
|
||||||
|
panic!("Attempted an out of bounds write for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col);
|
||||||
|
}
|
||||||
|
arr.data[position as usize] = queue.remove(0);
|
||||||
|
}
|
||||||
|
"read" =>
|
||||||
|
{
|
||||||
|
let position: i64 = queue.remove(0).parse::<i64>().unwrap();
|
||||||
|
if position >= arr.length
|
||||||
|
{
|
||||||
|
panic!("Attempted an out of bounds read for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col);
|
||||||
|
}
|
||||||
|
queue.push(arr.data[position as usize].clone());
|
||||||
|
}
|
||||||
|
"length" =>
|
||||||
|
{
|
||||||
|
queue.push(arr.length.to_string());
|
||||||
|
}
|
||||||
|
_ => panic!("Unexpected application '{}' at {}:{}", word, line, col)
|
||||||
|
}
|
||||||
|
}
|
||||||
Operation::While(while_block, _, _) =>
|
Operation::While(while_block, _, _) =>
|
||||||
{
|
{
|
||||||
loop
|
loop
|
||||||
@ -330,7 +380,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
output += interpret_program(while_block, queue, functions, intrinsics, debug).as_str();
|
output += interpret_program(while_block, queue, functions, arrays, intrinsics, debug).as_str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::Depth(_, _) =>
|
Operation::Depth(_, _) =>
|
||||||
@ -351,7 +401,7 @@ fn interpret_program(operations: &Vec<Operation>, queue: &mut Vec<String>, funct
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, 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>
|
||||||
{
|
{
|
||||||
for function in functions
|
for function in functions
|
||||||
{
|
{
|
||||||
@ -359,7 +409,7 @@ fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics:
|
|||||||
{
|
{
|
||||||
println!("Now typechecking function '{}'", function.name);
|
println!("Now typechecking function '{}'", function.name);
|
||||||
}
|
}
|
||||||
typecheck_block(&function.content, &function.ins, &function.outs, functions, intrinsics, debug)?;
|
typecheck_block(&function.content, &function.ins, &function.outs, functions, intrinsics, arrays, debug)?;
|
||||||
if debug
|
if debug
|
||||||
{
|
{
|
||||||
println!("Successfully typechecked function '{}'", function.name);
|
println!("Successfully typechecked function '{}'", function.name);
|
||||||
@ -369,7 +419,7 @@ fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics:
|
|||||||
{
|
{
|
||||||
println!("Now typechecking main operations");
|
println!("Now typechecking main operations");
|
||||||
}
|
}
|
||||||
typecheck_block(operations, &Vec::new(), &Vec::new(), functions, intrinsics, debug)?;
|
typecheck_block(operations, &Vec::new(), &Vec::new(), functions, intrinsics, arrays, debug)?;
|
||||||
if debug
|
if debug
|
||||||
{
|
{
|
||||||
println!("Successfully typechecked main operations");
|
println!("Successfully typechecked main operations");
|
||||||
@ -377,9 +427,9 @@ fn typecheck(operations: &Vec<Operation>, functions: &Vec<Function>, intrinsics:
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn typecheck_block(operations: &Vec<Operation>, ins: &Vec<Datatype>, outs: &Vec<Datatype>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<(), String>
|
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>
|
||||||
{
|
{
|
||||||
let actual_outs = get_return_type(operations, ins, functions, intrinsics, debug)?;
|
let actual_outs = get_return_type(operations, ins, functions, intrinsics, arrays, debug)?;
|
||||||
if &actual_outs != outs
|
if &actual_outs != outs
|
||||||
{
|
{
|
||||||
let (line, col) = match operations.last()
|
let (line, col) = match operations.last()
|
||||||
@ -398,6 +448,7 @@ fn typecheck_block(operations: &Vec<Operation>, ins: &Vec<Datatype>, outs: &Vec<
|
|||||||
Operation::Intrinsic(_, line, col) |
|
Operation::Intrinsic(_, line, col) |
|
||||||
Operation::While(_, line, col) |
|
Operation::While(_, line, col) |
|
||||||
Operation::QueueDiagnostic(line, col) |
|
Operation::QueueDiagnostic(line, col) |
|
||||||
|
Operation::Apply(_, _, line, col) |
|
||||||
Operation::Depth(line, col) => (*line, *col),
|
Operation::Depth(line, col) => (*line, *col),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -408,7 +459,7 @@ fn typecheck_block(operations: &Vec<Operation>, ins: &Vec<Datatype>, outs: &Vec<
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions: &Vec<Function>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<Vec<Datatype>, String>
|
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>
|
||||||
{
|
{
|
||||||
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);
|
||||||
@ -457,12 +508,12 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|||||||
{
|
{
|
||||||
if type_queue.is_empty()
|
if type_queue.is_empty()
|
||||||
{
|
{
|
||||||
panic!("Attempted to get the first element for a swap while the queue was empty at {}:{}", line, col);
|
return Err(format!("Attempted to get the first element for a swap while the queue was empty at {}:{}", line, col));
|
||||||
}
|
}
|
||||||
let first_typ = type_queue.remove(0);
|
let first_typ = type_queue.remove(0);
|
||||||
if type_queue.is_empty()
|
if type_queue.is_empty()
|
||||||
{
|
{
|
||||||
panic!("Attempted to get the second element for a swap while the queue was empty at {}:{}", line, col);
|
return Err(format!("Attempted to get the second element for a swap while the queue was empty at {}:{}", line, col));
|
||||||
}
|
}
|
||||||
let second_typ = type_queue.remove(0);
|
let second_typ = type_queue.remove(0);
|
||||||
type_queue.push(second_typ);
|
type_queue.push(second_typ);
|
||||||
@ -500,7 +551,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, 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
|
||||||
{
|
{
|
||||||
@ -508,7 +559,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, debug)?
|
get_return_type(else_block, &type_queue, functions, intrinsics, arrays, debug)?
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -547,7 +598,7 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|||||||
let comparison_type = type_queue.remove(0);
|
let comparison_type = type_queue.remove(0);
|
||||||
if comparison_type != Datatype::Bool
|
if comparison_type != Datatype::Bool
|
||||||
{
|
{
|
||||||
panic!("Expected a Bool as a while condition but got {:?} instead at {}:{}", comparison_type, line, col);
|
return Err(format!("Expected a Bool as a while condition but got {:?} instead at {}:{}", comparison_type, line, col));
|
||||||
}
|
}
|
||||||
if debug
|
if debug
|
||||||
{
|
{
|
||||||
@ -555,7 +606,7 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|||||||
}
|
}
|
||||||
let mut outs = type_queue.clone();
|
let mut outs = type_queue.clone();
|
||||||
outs.insert(0, Datatype::Bool);
|
outs.insert(0, Datatype::Bool);
|
||||||
typecheck_block(while_block, type_queue, &outs, functions, intrinsics, debug)?;
|
typecheck_block(while_block, type_queue, &outs, functions, intrinsics, arrays, debug)?;
|
||||||
}
|
}
|
||||||
Operation::Depth(_, _) =>
|
Operation::Depth(_, _) =>
|
||||||
{
|
{
|
||||||
@ -565,6 +616,39 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|||||||
{
|
{
|
||||||
println!("---Type queue state at {}:{}---\nlength: {}\n{:?}\n------------------------------", line, col, type_queue.len(), type_queue);
|
println!("---Type queue state at {}:{}---\nlength: {}\n{:?}\n------------------------------", line, col, type_queue.len(), type_queue);
|
||||||
}
|
}
|
||||||
|
Operation::Apply(name, word, line, col) =>
|
||||||
|
{
|
||||||
|
match word.as_str()
|
||||||
|
{
|
||||||
|
"write" =>
|
||||||
|
{
|
||||||
|
if type_queue.is_empty() || type_queue.remove(0) != Datatype::Int
|
||||||
|
{
|
||||||
|
return Err(format!("Expected a position for a write application at {}:{}", line, col));
|
||||||
|
}
|
||||||
|
let expected_type = arrays.iter().find(|x| &x.name == name).unwrap().datatype;
|
||||||
|
let actual_type = type_queue.remove(0);
|
||||||
|
if actual_type != expected_type
|
||||||
|
{
|
||||||
|
return Err(format!("Expected a {:?} value but got a {:?} value at {}:{}", expected_type, actual_type, line, col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"read" =>
|
||||||
|
{
|
||||||
|
if type_queue.is_empty() || type_queue.remove(0) != Datatype::Int
|
||||||
|
{
|
||||||
|
return Err(format!("Expected a position for a read application at {}:{}", line, col));
|
||||||
|
}
|
||||||
|
let typ = arrays.iter().find(|x| &x.name == name).unwrap().datatype;
|
||||||
|
type_queue.push(typ);
|
||||||
|
}
|
||||||
|
"length" =>
|
||||||
|
{
|
||||||
|
type_queue.push(Datatype::Int);
|
||||||
|
}
|
||||||
|
_ => return Err(format!("Encountered unknown application '{}' at {}:{}", word, line, col))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if debug
|
if debug
|
||||||
{
|
{
|
||||||
@ -574,17 +658,17 @@ fn get_return_type(operations: &Vec<Operation>, ins: &Vec<Datatype>, functions:
|
|||||||
return Ok(type_queue.clone());
|
return Ok(type_queue.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_function_calls(operations: &Vec<Operation>, functions: &Vec<Function>, debug: bool) -> Result<(), String>
|
fn validate_function_calls(operations: &Vec<Operation>, functions: &Vec<Function>, arrays: &Vec<Arr>, debug: bool) -> Result<(), String>
|
||||||
{
|
{
|
||||||
for function in functions
|
for function in functions
|
||||||
{
|
{
|
||||||
validate_function_calls_in_block(&function.content, functions, debug)?;
|
validate_function_calls_in_block(&function.content, functions, arrays, debug)?;
|
||||||
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, debug)?;
|
validate_function_calls_in_block(operations, functions, arrays, debug)?;
|
||||||
if debug
|
if debug
|
||||||
{
|
{
|
||||||
println!("Successfully validated function calls in main operations");
|
println!("Successfully validated function calls in main operations");
|
||||||
@ -592,14 +676,14 @@ fn validate_function_calls(operations: &Vec<Operation>, functions: &Vec<Function
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_function_calls_in_block(block: &Vec<Operation>, functions: &Vec<Function>, debug: bool) -> Result<(), String>
|
fn validate_function_calls_in_block(block: &Vec<Operation>, functions: &Vec<Function>, arrays: &Vec<Arr>, debug: bool) -> Result<(), String>
|
||||||
{
|
{
|
||||||
for operation in block
|
for operation in block
|
||||||
{
|
{
|
||||||
match operation
|
match operation
|
||||||
{
|
{
|
||||||
Operation::Depth(_, _) | Operation::QueueDiagnostic(_, _) | Operation::Intrinsic(_, _, _) | Operation::Enqueue(_, _, _, _) | Operation::Dequeue(_, _) |
|
Operation::Depth(_, _) | Operation::QueueDiagnostic(_, _) | Operation::Intrinsic(_, _, _) | Operation::Enqueue(_, _, _, _) | Operation::Dequeue(_, _) |
|
||||||
Operation::Requeue(_, _) | Operation::Dup(_, _) | Operation::Swap(_, _) => {},
|
Operation::Requeue(_, _) | Operation::Dup(_, _) | Operation::Swap(_, _) | Operation::Apply(_, _, _, _) => {},
|
||||||
Operation::FunctionCall(function_name, line, col) =>
|
Operation::FunctionCall(function_name, line, col) =>
|
||||||
{
|
{
|
||||||
if !functions.iter().any(|x| &x.name == function_name)
|
if !functions.iter().any(|x| &x.name == function_name)
|
||||||
@ -609,21 +693,129 @@ 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, debug)?;
|
validate_function_calls_in_block(if_block, functions, arrays, debug)?;
|
||||||
if let Some(else_block) = maybe_else_block
|
if let Some(else_block) = maybe_else_block
|
||||||
{
|
{
|
||||||
validate_function_calls_in_block(else_block, functions, debug)?;
|
validate_function_calls_in_block(else_block, functions, arrays, debug)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::While(while_block, _, _) =>
|
Operation::While(while_block, _, _) =>
|
||||||
{
|
{
|
||||||
validate_function_calls_in_block(while_block, functions, debug)?;
|
validate_function_calls_in_block(while_block, functions, arrays, debug)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn extract_arrays(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, functions: &Vec<Function>, debug: bool) -> Result<Vec<Arr>, String>
|
||||||
|
{
|
||||||
|
let mut tokens_iter = tokens.iter().peekable();
|
||||||
|
let mut arrays: Vec<Arr> = Vec::new();
|
||||||
|
let mut new_tokens: Vec<Token> = Vec::new();
|
||||||
|
while let Some(token) = tokens_iter.next()
|
||||||
|
{
|
||||||
|
if let Token::Keyword(word, line, col) = token
|
||||||
|
{
|
||||||
|
if word == "arr"
|
||||||
|
{
|
||||||
|
if debug
|
||||||
|
{
|
||||||
|
println!("Found an array at {}:{}", line, col);
|
||||||
|
}
|
||||||
|
if let Some(Token::Keyword(name, _, _)) = tokens_iter.next()
|
||||||
|
{
|
||||||
|
if functions.iter().any(|x| &x.name == name)
|
||||||
|
{
|
||||||
|
return Err(format!("Cannot redeclare an array with the same name as a function {}:{}", line, col));
|
||||||
|
}
|
||||||
|
if arrays.iter().any(|x| &x.name == name)
|
||||||
|
{
|
||||||
|
return Err(format!("Cannot redeclare an array with the same name as an array {}:{}", line, col));
|
||||||
|
}
|
||||||
|
if intrinsics.contains_key(name.as_str())
|
||||||
|
{
|
||||||
|
return Err(format!("An array cannot have the same name as an intrinsic ({}) at {}:{}", name, line, col));
|
||||||
|
}
|
||||||
|
if let Some(Token::Keyword(open_curly, _, _)) = tokens_iter.next()
|
||||||
|
{
|
||||||
|
if open_curly != "{"
|
||||||
|
{
|
||||||
|
return Err(format!("Expected '{{' in array declaration at {}:{}", line, col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Err(format!("Reached the end of the file while parsing an array at {}:{}", line, col));
|
||||||
|
}
|
||||||
|
if let Some(Token::Keyword(typ, _, _)) = tokens_iter.next()
|
||||||
|
{
|
||||||
|
let datatype = str_to_datatype(typ, *line, *col)?;
|
||||||
|
if let Some(Token::IntLit(size_str, _, _)) = tokens_iter.next()
|
||||||
|
{
|
||||||
|
let size = size_str.parse::<i64>().unwrap();
|
||||||
|
if let Some(Token::Keyword(close_curly, _, _)) = tokens_iter.next()
|
||||||
|
{
|
||||||
|
if close_curly != "}"
|
||||||
|
{
|
||||||
|
return Err(format!("Expected '}}' in array declaration at {}:{}", line, col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Err(format!("Reached the end of the file while parsing an array at {}:{}", line, col));
|
||||||
|
}
|
||||||
|
let mut data: Vec<String> = Vec::new();
|
||||||
|
let default_val = match datatype
|
||||||
|
{
|
||||||
|
Datatype::Any | Datatype::String => String::new(),
|
||||||
|
Datatype::Bool => String::from("false"),
|
||||||
|
Datatype::Int => String::from("0"),
|
||||||
|
};
|
||||||
|
for _ in 0..size
|
||||||
|
{
|
||||||
|
data.push(default_val.clone());
|
||||||
|
}
|
||||||
|
arrays.push(Arr { name: name.clone(), datatype, length: size , data });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Err(format!("Reached the end of the file while parsing an array at {}:{}", line, col))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Err(format!("Expected array name, at {}:{}", line, col));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_tokens.push(token.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
new_tokens.push(token.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tokens.clear();
|
||||||
|
tokens.extend_from_slice(&new_tokens);
|
||||||
|
return Ok(arrays);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn str_to_datatype(s: &str, line: i32, col: i32) -> Result<Datatype, String>
|
||||||
|
{
|
||||||
|
match s
|
||||||
|
{
|
||||||
|
"any" => Ok(Datatype::Any),
|
||||||
|
"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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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>, intrinsics: &HashMap<&str, (Vec<Datatype>, Vec<Datatype>)>, debug: bool) -> Result<Vec<Function>, String>
|
||||||
{
|
{
|
||||||
let mut tokens_iter = tokens.iter().peekable();
|
let mut tokens_iter = tokens.iter().peekable();
|
||||||
@ -649,7 +841,8 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|||||||
{
|
{
|
||||||
match token
|
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::Apply(_, _, line, col) =>
|
||||||
{
|
{
|
||||||
return Err(format!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col));
|
return Err(format!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col));
|
||||||
}
|
}
|
||||||
@ -687,7 +880,8 @@ fn extract_functions(tokens: &mut Vec<Token>, intrinsics: &HashMap<&str, (Vec<Da
|
|||||||
{
|
{
|
||||||
match token
|
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::Apply(_, _, line, col) =>
|
||||||
{
|
{
|
||||||
return Err(format!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col));
|
return Err(format!("Expected input parameters for a function but got {:?} instead at {}:{}", token, line, col));
|
||||||
}
|
}
|
||||||
@ -781,6 +975,10 @@ fn parse_until_delimiter(tokens_iter: &mut Peekable<std::slice::Iter<Token>>, in
|
|||||||
{
|
{
|
||||||
operations.push(Operation::Enqueue(Datatype::Bool, value.clone(), *line, *col));
|
operations.push(Operation::Enqueue(Datatype::Bool, value.clone(), *line, *col));
|
||||||
}
|
}
|
||||||
|
Token::Apply(name, word, line, col) =>
|
||||||
|
{
|
||||||
|
operations.push(Operation::Apply(name.clone(), word.clone(), *line, *col));
|
||||||
|
}
|
||||||
Token::Keyword(word, line, col) =>
|
Token::Keyword(word, line, col) =>
|
||||||
{
|
{
|
||||||
if intrinsics.contains_key(word.as_str())
|
if intrinsics.contains_key(word.as_str())
|
||||||
@ -881,6 +1079,7 @@ fn tokenize(text: &str) -> Result<Vec<Token>, String>
|
|||||||
let mut state = TokenizerState::Whitespace;
|
let mut state = TokenizerState::Whitespace;
|
||||||
let mut word = String::new();
|
let mut word = String::new();
|
||||||
let mut iter = text.chars().peekable();
|
let mut iter = text.chars().peekable();
|
||||||
|
let mut application_name = String::new();
|
||||||
while let Some(ch) = iter.next()
|
while let Some(ch) = iter.next()
|
||||||
{
|
{
|
||||||
if ch == '/' && iter.peek() == Some(&'/')
|
if ch == '/' && iter.peek() == Some(&'/')
|
||||||
@ -933,17 +1132,25 @@ fn tokenize(text: &str) -> Result<Vec<Token>, String>
|
|||||||
if ch.is_whitespace()
|
if ch.is_whitespace()
|
||||||
{
|
{
|
||||||
state = TokenizerState::Whitespace;
|
state = TokenizerState::Whitespace;
|
||||||
if let Ok(_) = word.parse::<i64>()
|
if application_name.is_empty()
|
||||||
{
|
{
|
||||||
tokens.push(Token::IntLit(word.clone(), line, col));
|
if let Ok(_) = word.parse::<i64>()
|
||||||
}
|
{
|
||||||
else if word == "true" || word == "false"
|
tokens.push(Token::IntLit(word.clone(), line, col));
|
||||||
{
|
}
|
||||||
tokens.push(Token::BoolLit(word.clone(), line, col));
|
else if word == "true" || word == "false"
|
||||||
|
{
|
||||||
|
tokens.push(Token::BoolLit(word.clone(), line, col));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tokens.push(Token::Keyword(word.clone(), line, col));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tokens.push(Token::Keyword(word.clone(), line, col));
|
tokens.push(Token::Apply(application_name.clone(), word.clone(), line, col));
|
||||||
|
application_name.clear();
|
||||||
}
|
}
|
||||||
word.clear();
|
word.clear();
|
||||||
}
|
}
|
||||||
@ -952,6 +1159,11 @@ 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(format!("Having '\"' in the middle of a word is not allowed")),
|
||||||
|
'.' =>
|
||||||
|
{
|
||||||
|
application_name = word.clone();
|
||||||
|
word.clear();
|
||||||
|
}
|
||||||
_ =>
|
_ =>
|
||||||
{
|
{
|
||||||
word.push(ch);
|
word.push(ch);
|
||||||
|
@ -1,4 +1,15 @@
|
|||||||
//valid,:END:
|
//valid,00000000000000110000000000000000
|
||||||
|
//00000000000001110000000000000000
|
||||||
|
//00000000000011010000000000000000
|
||||||
|
//00000000000111110000000000000000
|
||||||
|
//00000000001100010000000000000000
|
||||||
|
//00000000011100110000000000000000
|
||||||
|
//00000000110101110000000000000000
|
||||||
|
//00000001111111010000000000000000
|
||||||
|
//00000011000001110000000000000000
|
||||||
|
//00000111000011010000000000000000
|
||||||
|
//00001101000111110000000000000000
|
||||||
|
//:END:
|
||||||
function bool bool bool => bool rule110
|
function bool bool bool => bool rule110
|
||||||
{
|
{
|
||||||
if
|
if
|
||||||
@ -24,9 +35,62 @@ function bool bool bool => bool rule110
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function int => bool intToBool
|
arr val { bool 32 }
|
||||||
|
|
||||||
|
15 true val.write
|
||||||
|
|
||||||
|
function int => bool int check
|
||||||
{
|
{
|
||||||
0 !=
|
0 dup 1 > -
|
||||||
|
}
|
||||||
|
|
||||||
|
function => fullApply
|
||||||
|
{
|
||||||
|
0 false val2.write
|
||||||
|
true 1
|
||||||
|
while
|
||||||
|
{
|
||||||
|
// i-1 i
|
||||||
|
1 dup - req
|
||||||
|
// i a | i a i | a i b | i b a i 1
|
||||||
|
val.read dup val.read req dup 1
|
||||||
|
// i a b i+1 | i+1 i a b | i a b c
|
||||||
|
req swp + req req req val.read
|
||||||
|
// i d
|
||||||
|
req rule110
|
||||||
|
// i d i | i
|
||||||
|
dup val2.write
|
||||||
|
checkUp-1
|
||||||
|
}
|
||||||
|
1 - false val2.write
|
||||||
|
}
|
||||||
|
|
||||||
|
function int => bool int checkUp
|
||||||
|
{
|
||||||
|
// i+1 l i+1
|
||||||
|
1 + val.length dup < req
|
||||||
|
}
|
||||||
|
|
||||||
|
function int => bool int checkUp-1
|
||||||
|
{
|
||||||
|
// i+1 l 1 | l 1 i+1 | i+1 l-1 i+1
|
||||||
|
1 + val.length 1 req - dup
|
||||||
|
// i+1 b
|
||||||
|
< req
|
||||||
|
}
|
||||||
|
|
||||||
|
arr val2 { bool 32 }
|
||||||
|
|
||||||
|
function => copyArrays
|
||||||
|
{
|
||||||
|
true 0
|
||||||
|
while
|
||||||
|
{
|
||||||
|
dup val2.read
|
||||||
|
dup val.write
|
||||||
|
checkUp
|
||||||
|
}
|
||||||
|
deq
|
||||||
}
|
}
|
||||||
|
|
||||||
function bool => int boolToInt
|
function bool => int boolToInt
|
||||||
@ -41,49 +105,24 @@ function bool => int boolToInt
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
true 10
|
function => printArrays
|
||||||
|
|
||||||
true 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
||||||
|
|
||||||
while
|
|
||||||
{
|
{
|
||||||
check
|
true 0
|
||||||
while
|
while
|
||||||
{
|
{
|
||||||
// 32 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
dup val.read req boolToInt req print
|
||||||
checkAndApply
|
checkUp
|
||||||
// 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 true 31 0 0 0
|
|
||||||
shift-5
|
|
||||||
}
|
}
|
||||||
|
deq
|
||||||
|
"" println
|
||||||
}
|
}
|
||||||
|
|
||||||
function any any any any any any any any any any any any any any any any any any any any any any any any any any any => any any any any any any any any any any any any any any any any any any any any any any any any any any any shift-5
|
true 10
|
||||||
{ }
|
while
|
||||||
|
|
||||||
function int int int int => bool int int int int checkAndApply
|
|
||||||
{
|
{
|
||||||
check apply
|
fullApply
|
||||||
}
|
copyArrays
|
||||||
|
printArrays
|
||||||
function int => bool int
|
check
|
||||||
{
|
|
||||||
0 dup 1 > req -
|
|
||||||
}
|
|
||||||
|
|
||||||
function int int int => int int int apply
|
|
||||||
{
|
|
||||||
// a b c
|
|
||||||
intToBool
|
|
||||||
// b c d
|
|
||||||
dup intToBool
|
|
||||||
// c d b e
|
|
||||||
dup intToBool
|
|
||||||
// d b e c f
|
|
||||||
req swp swp
|
|
||||||
// d e b f c
|
|
||||||
req req swp
|
|
||||||
// c d e f b
|
|
||||||
req rule110
|
|
||||||
// b c g
|
|
||||||
req req boolToInt
|
|
||||||
}
|
}
|
||||||
|
deq
|
Loading…
x
Reference in New Issue
Block a user