Split parser from runtime.

This commit is contained in:
abbie 2024-08-21 21:15:39 +01:00
parent b415d858c0
commit 90aaeb8adb
Signed by: threeoh6000
GPG key ID: 801FE4AD456E922C
3 changed files with 8 additions and 126 deletions

6
Cargo.lock generated
View file

@ -102,6 +102,7 @@ name = "granite"
version = "1.1.0-develop"
dependencies = [
"clap",
"parsegranite",
]
[[package]]
@ -116,6 +117,11 @@ version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "parsegranite"
version = "1.1.0-develop"
source = "git+https://git.colean.cc/threeoh6000/parsegranite?rev=5eaca18#5eaca1898f64ea890092a3a33e8f3c1655eab7e3"
[[package]]
name = "proc-macro2"
version = "1.0.86"

View file

@ -5,3 +5,4 @@ edition = "2021"
[dependencies]
clap = { version = "4.5.15", features = ["derive"] }
parsegranite = { git = "https://git.colean.cc/threeoh6000/parsegranite", rev = "5eaca18", version = "1.1.0-develop" }

View file

@ -4,18 +4,7 @@ use std::process::exit;
use std::io;
use std::io::Write;
use std::fs;
#[derive(Debug)]
struct Statement {
operator: String,
arguments: Vec<String>,
}
#[derive(Debug)]
struct Program {
statements: Vec<Statement>,
labels: HashMap<String, usize>,
}
use parsegranite::{parse, Program};
/// A toy programming language runtime.
#[derive(Parser, Debug)]
@ -301,117 +290,3 @@ fn execute(program: Program) {
current_statement = current_statement + 1;
}
}
fn parse(data: &str) -> Result<Program, String> {
let mut program_begun = false;
let mut operator: Option<String> = None;
let mut arguments: Vec<String> = vec![];
let mut expected_arguments: i32 = -1;
let mut argument_builder: String = "".to_string();
let mut statements: Vec<Statement> = vec![];
let mut labels: HashMap<String, usize> = HashMap::new();
let mut inside_string = false;
let mut string_escape = false;
for char in data.chars() {
if !program_begun && char == ':' {
program_begun = true;
} else if program_begun {
if operator.is_none() {
let potential_argument_length = operator_to_arglength(char.clone());
if potential_argument_length.is_none() { return Err(format!("Invalid operator {} at statement {}.", char, statements.len())); }
expected_arguments = potential_argument_length.unwrap();
operator = Some(char.to_string());
} else if expected_arguments > 0 {
if inside_string {
if char == '"' && !string_escape {
inside_string = false;
} else {
if char == '\\' {
if !string_escape { string_escape = true; }
else {
argument_builder = format!("{}{}", argument_builder, char);
string_escape = false;
}
} else {
argument_builder = format!("{}{}", argument_builder, char);
string_escape = false;
}
}
} else if char == ',' {
expected_arguments = expected_arguments - 1;
arguments.push(argument_builder);
argument_builder = "".to_string();
} else if char == ':' && !inside_string {
expected_arguments = expected_arguments - 1;
arguments.push(argument_builder);
argument_builder = "".to_string();
if expected_arguments != 0 {
return Err(format!("Invalid amount of arguments for operator {} at {}.", operator.unwrap(), statements.len()));
}
} else if char == '"' {
if argument_builder.len() != 0 { return Err(format!("Cannot start string where argument already exists at {}.", statements.len())); }
inside_string = true;
} else if char == '\n' && !inside_string {
continue;
} else {
argument_builder = format!("{}{}", argument_builder, char);
}
}
if operator.is_some() && char == ':' && !inside_string {
let new_statement = Statement { operator: operator.clone().unwrap(), arguments: arguments.clone() };
statements.push(new_statement);
if operator.clone().unwrap() == "@" {
labels.insert(statements[statements.len()-1].arguments[0].clone(), statements.len()-1);
}
operator = None;
arguments = vec![];
argument_builder = "".to_string();
expected_arguments = -1;
}
}
}
if argument_builder.len() != 0 {
arguments.push(argument_builder);
expected_arguments = expected_arguments - 1;
}
if expected_arguments != 0 {
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() };
statements.push(new_statement);
let program = Program { statements: statements, labels: labels };
Ok(program)
}
fn operator_to_arglength(operator: char) -> Option<i32> {
match operator {
'>' => Some(2),
'?' => Some(1),
'!' => Some(1),
'~' => Some(0),
'<' => Some(1),
'^' => Some(1),
'v' => Some(1),
'@' => Some(1),
'+' => Some(3),
'-' => Some(3),
'=' => Some(3),
'*' => Some(3),
'a' => Some(3),
's' => Some(3),
'm' => Some(3),
'd' => Some(3),
'0' => Some(1),
'&' => Some(2),
'$' => Some(1),
'%' => Some(2),
'#' => Some(0),
'|' => Some(0),
_ => None,
}
}