Construct operators as an enum

This commit is contained in:
abbie 2024-08-21 21:49:11 +01:00
parent 5eaca1898f
commit 95eeeb6ec7
Signed by: threeoh6000
GPG key ID: 801FE4AD456E922C

View file

@ -1,8 +1,34 @@
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Debug, PartialEq, Clone)]
pub enum Operator {
SetVariable,
Increment,
Decrement,
Print,
NewLabel,
UnconditionalJump,
JumpIfLessThan,
JumpIfGreaterThan,
JumpIfEqualTo,
ArithmeticAdd,
ArithmeticSubtract,
ArithmeticMultiply,
ArithmeticDivide,
TakeInput,
Comment,
StringConcatenation,
ExplicitExit,
TypeCheck,
StackPush,
Return,
VariableClone,
VariableDrop,
}
#[derive(Debug)] #[derive(Debug)]
pub struct Statement { pub struct Statement {
pub operator: String, pub operator: Operator,
pub arguments: Vec<String>, pub arguments: Vec<String>,
} }
@ -14,7 +40,7 @@ pub struct Program {
pub fn parse(data: &str) -> Result<Program, String> { pub fn parse(data: &str) -> Result<Program, String> {
let mut program_begun = false; let mut program_begun = false;
let mut operator: Option<String> = None; let mut operator: Option<Operator> = None;
let mut arguments: Vec<String> = vec![]; let mut arguments: Vec<String> = vec![];
let mut expected_arguments: i32 = -1; let mut expected_arguments: i32 = -1;
let mut argument_builder: String = "".to_string(); let mut argument_builder: String = "".to_string();
@ -29,10 +55,9 @@ pub fn parse(data: &str) -> Result<Program, String> {
program_begun = true; program_begun = true;
} else if program_begun { } else if program_begun {
if operator.is_none() { if operator.is_none() {
let potential_argument_length = operator_to_arglength(char.clone()); let (operator, potential_argument_length) = operator_to_arglength(char.clone());
if potential_argument_length.is_none() { return Err(format!("Invalid operator {} at statement {}.", char, statements.len())); } if potential_argument_length.is_none() { return Err(format!("Invalid operator {} at statement {}.", char, statements.len())); }
expected_arguments = potential_argument_length.unwrap(); expected_arguments = potential_argument_length.unwrap();
operator = Some(char.to_string());
} else if expected_arguments > 0 { } else if expected_arguments > 0 {
if inside_string { if inside_string {
if char == '"' && !string_escape { if char == '"' && !string_escape {
@ -58,7 +83,7 @@ pub fn parse(data: &str) -> Result<Program, String> {
arguments.push(argument_builder); arguments.push(argument_builder);
argument_builder = "".to_string(); argument_builder = "".to_string();
if expected_arguments != 0 { if expected_arguments != 0 {
return Err(format!("Invalid amount of arguments for operator {} at {}.", operator.unwrap(), statements.len())); return Err(format!("Invalid amount of arguments for operator {:?} at {}.", operator.unwrap(), statements.len()));
} }
} else if char == '"' { } else if char == '"' {
if argument_builder.len() != 0 { return Err(format!("Cannot start string where argument already exists at {}.", statements.len())); } if argument_builder.len() != 0 { return Err(format!("Cannot start string where argument already exists at {}.", statements.len())); }
@ -72,7 +97,7 @@ pub fn parse(data: &str) -> Result<Program, String> {
if operator.is_some() && char == ':' && !inside_string { if operator.is_some() && char == ':' && !inside_string {
let new_statement = Statement { operator: operator.clone().unwrap(), arguments: arguments.clone() }; let new_statement = Statement { operator: operator.clone().unwrap(), arguments: arguments.clone() };
statements.push(new_statement); statements.push(new_statement);
if operator.clone().unwrap() == "@" { if operator.clone().unwrap() == Operator::NewLabel {
labels.insert(statements[statements.len()-1].arguments[0].clone(), statements.len()-1); labels.insert(statements[statements.len()-1].arguments[0].clone(), statements.len()-1);
} }
operator = None; operator = None;
@ -88,7 +113,7 @@ pub fn parse(data: &str) -> Result<Program, String> {
} }
if expected_arguments != 0 { if expected_arguments != 0 {
return Err(format!("Invalid amount of arguments for operator {} at {}.", operator.unwrap(), statements.len())); return Err(format!("Invalid amount of arguments for operator {:?} at {}.", operator.unwrap(), statements.len()));
} }
let new_statement = Statement { operator: operator.unwrap().clone(), arguments: arguments.clone() }; let new_statement = Statement { operator: operator.unwrap().clone(), arguments: arguments.clone() };
statements.push(new_statement); statements.push(new_statement);
@ -98,30 +123,30 @@ pub fn parse(data: &str) -> Result<Program, String> {
Ok(program) Ok(program)
} }
fn operator_to_arglength(operator: char) -> Option<i32> { fn operator_to_arglength(operator: char) -> (Option<Operator>, Option<i32>) {
match operator { match operator {
'>' => Some(2), '>' => (Some(Operator::SetVariable), Some(2)),
'?' => Some(1), '?' => (Some(Operator::TakeInput), Some(1)),
'!' => Some(1), '!' => (Some(Operator::Print), Some(1)),
'~' => Some(0), '~' => (Some(Operator::ExplicitExit), Some(0)),
'<' => Some(1), '<' => (Some(Operator::UnconditionalJump), Some(1)),
'^' => Some(1), '^' => (Some(Operator::Increment), Some(1)),
'v' => Some(1), 'v' => (Some(Operator::Decrement), Some(1)),
'@' => Some(1), '@' => (Some(Operator::NewLabel), Some(1)),
'+' => Some(3), '+' => (Some(Operator::JumpIfGreaterThan), Some(3)),
'-' => Some(3), '-' => (Some(Operator::JumpIfLessThan), Some(3)),
'=' => Some(3), '=' => (Some(Operator::JumpIfEqualTo), Some(3)),
'*' => Some(3), '*' => (Some(Operator::StringConcatenation), Some(3)),
'a' => Some(3), 'a' => (Some(Operator::ArithmeticAdd), Some(3)),
's' => Some(3), 's' => (Some(Operator::ArithmeticSubtract), Some(3)),
'm' => Some(3), 'm' => (Some(Operator::ArithmeticMultiply), Some(3)),
'd' => Some(3), 'd' => (Some(Operator::ArithmeticDivide), Some(3)),
'0' => Some(1), '0' => (Some(Operator::Comment), Some(1)),
'&' => Some(2), '&' => (Some(Operator::TypeCheck), Some(2)),
'$' => Some(1), '$' => (Some(Operator::VariableDrop), Some(1)),
'%' => Some(2), '%' => (Some(Operator::VariableClone), Some(2)),
'#' => Some(0), '#' => (Some(Operator::StackPush), Some(0)),
'|' => Some(0), '|' => (Some(Operator::Return), Some(0)),
_ => None, _ => (None, None),
} }
} }