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"
|
version = "1.1.0-develop"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
|
"parsegranite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -116,6 +117,11 @@ version = "1.70.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parsegranite"
|
||||||
|
version = "1.1.0-develop"
|
||||||
|
source = "git+https://git.colean.cc/threeoh6000/parsegranite?rev=5eaca18#5eaca1898f64ea890092a3a33e8f3c1655eab7e3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.86"
|
version = "1.0.86"
|
||||||
|
|
|
@ -5,3 +5,4 @@ edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5.15", features = ["derive"] }
|
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;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use parsegranite::{parse, Program};
|
||||||
#[derive(Debug)]
|
|
||||||
struct Statement {
|
|
||||||
operator: String,
|
|
||||||
arguments: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct Program {
|
|
||||||
statements: Vec<Statement>,
|
|
||||||
labels: HashMap<String, usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A toy programming language runtime.
|
/// A toy programming language runtime.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
|
@ -301,117 +290,3 @@ fn execute(program: Program) {
|
||||||
current_statement = current_statement + 1;
|
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