Split parser from runtime.
This commit is contained in:
parent
b415d858c0
commit
90aaeb8adb
3 changed files with 8 additions and 126 deletions
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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" }
|
||||
|
|
127
src/main.rs
127
src/main.rs
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue