Compare commits
3 commits
Author | SHA1 | Date | |
---|---|---|---|
d36d8da0a7 | |||
90aaeb8adb | |||
b415d858c0 |
3 changed files with 34 additions and 152 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -53,9 +53,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.15"
|
version = "4.5.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc"
|
checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
@ -99,9 +99,10 @@ checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "granite"
|
name = "granite"
|
||||||
version = "1.0.3"
|
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=1a345d4#1a345d469398afdbfa0ab93608279ea802455c46"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.86"
|
version = "1.0.86"
|
||||||
|
@ -142,9 +148,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.74"
|
version = "2.0.75"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
|
checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "granite"
|
name = "granite"
|
||||||
version = "1.0.3"
|
version = "1.1.0-develop"
|
||||||
edition = "2021"
|
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 = "1a345d4", version = "1.1.0-develop" }
|
||||||
|
|
167
src/main.rs
167
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, Operator};
|
||||||
#[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)]
|
||||||
|
@ -55,9 +44,9 @@ fn execute(program: Program) {
|
||||||
loop {
|
loop {
|
||||||
if current_statement >= statements.len() { break; }
|
if current_statement >= statements.len() { break; }
|
||||||
let statement = &statements[current_statement];
|
let statement = &statements[current_statement];
|
||||||
if statement.operator == ">" {
|
if statement.operator == Operator::SetVariable {
|
||||||
vars.insert(statement.arguments[1].clone(), statement.arguments[0].clone());
|
vars.insert(statement.arguments[1].clone(), statement.arguments[0].clone());
|
||||||
} else if statement.operator == "^" {
|
} else if statement.operator == Operator::Increment {
|
||||||
if vars.contains_key(&statement.arguments[0]) {
|
if vars.contains_key(&statement.arguments[0]) {
|
||||||
let value = vars.get(&statement.arguments[0]).unwrap();
|
let value = vars.get(&statement.arguments[0]).unwrap();
|
||||||
let binding = value.parse::<i64>();
|
let binding = value.parse::<i64>();
|
||||||
|
@ -73,7 +62,7 @@ fn execute(program: Program) {
|
||||||
println!("Missing variable {}.", statement.arguments[0]);
|
println!("Missing variable {}.", statement.arguments[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "v" {
|
} else if statement.operator == Operator::Decrement {
|
||||||
if vars.contains_key(&statement.arguments[0]) {
|
if vars.contains_key(&statement.arguments[0]) {
|
||||||
let value = vars.get(&statement.arguments[0]).unwrap();
|
let value = vars.get(&statement.arguments[0]).unwrap();
|
||||||
let binding = value.parse::<i64>();
|
let binding = value.parse::<i64>();
|
||||||
|
@ -89,7 +78,7 @@ fn execute(program: Program) {
|
||||||
println!("Missing variable {}.", statement.arguments[0]);
|
println!("Missing variable {}.", statement.arguments[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "!" {
|
} else if statement.operator == Operator::Print {
|
||||||
if vars.contains_key(&statement.arguments[0]) {
|
if vars.contains_key(&statement.arguments[0]) {
|
||||||
let value = vars.get(&statement.arguments[0]).unwrap();
|
let value = vars.get(&statement.arguments[0]).unwrap();
|
||||||
println!("{}", value);
|
println!("{}", value);
|
||||||
|
@ -97,7 +86,7 @@ fn execute(program: Program) {
|
||||||
println!("Missing variable {}.", statement.arguments[0]);
|
println!("Missing variable {}.", statement.arguments[0]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "*" {
|
} else if statement.operator == Operator::StringConcatenation {
|
||||||
if vars.contains_key(&statement.arguments[0]) && vars.contains_key(&statement.arguments[1]) {
|
if vars.contains_key(&statement.arguments[0]) && vars.contains_key(&statement.arguments[1]) {
|
||||||
let left = vars.get(&statement.arguments[0]).unwrap();
|
let left = vars.get(&statement.arguments[0]).unwrap();
|
||||||
let right = vars.get(&statement.arguments[1]).unwrap();
|
let right = vars.get(&statement.arguments[1]).unwrap();
|
||||||
|
@ -106,7 +95,7 @@ fn execute(program: Program) {
|
||||||
println!("Missing variable.");
|
println!("Missing variable.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "+" {
|
} else if statement.operator == Operator::JumpIfGreaterThan {
|
||||||
if vars.contains_key(&statement.arguments[1]) && labels.contains_key(&statement.arguments[0]) {
|
if vars.contains_key(&statement.arguments[1]) && labels.contains_key(&statement.arguments[0]) {
|
||||||
let binding;
|
let binding;
|
||||||
if vars.contains_key(&statement.arguments[2]) {
|
if vars.contains_key(&statement.arguments[2]) {
|
||||||
|
@ -130,7 +119,7 @@ fn execute(program: Program) {
|
||||||
println!("Missing variable or label.");
|
println!("Missing variable or label.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "-" {
|
} else if statement.operator == Operator::JumpIfLessThan {
|
||||||
if vars.contains_key(&statement.arguments[1]) && labels.contains_key(&statement.arguments[0]) {
|
if vars.contains_key(&statement.arguments[1]) && labels.contains_key(&statement.arguments[0]) {
|
||||||
let binding;
|
let binding;
|
||||||
if vars.contains_key(&statement.arguments[2]) {
|
if vars.contains_key(&statement.arguments[2]) {
|
||||||
|
@ -155,7 +144,7 @@ fn execute(program: Program) {
|
||||||
println!("Missing variable or label.");
|
println!("Missing variable or label.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "=" {
|
} else if statement.operator == Operator::JumpIfEqualTo {
|
||||||
if vars.contains_key(&statement.arguments[1]) && labels.contains_key(&statement.arguments[0]) {
|
if vars.contains_key(&statement.arguments[1]) && labels.contains_key(&statement.arguments[0]) {
|
||||||
let binding;
|
let binding;
|
||||||
if vars.contains_key(&statement.arguments[2]) {
|
if vars.contains_key(&statement.arguments[2]) {
|
||||||
|
@ -179,7 +168,7 @@ fn execute(program: Program) {
|
||||||
println!("Missing variable or label.");
|
println!("Missing variable or label.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "<" {
|
} else if statement.operator == Operator::UnconditionalJump {
|
||||||
if labels.contains_key(&statement.arguments[0]) {
|
if labels.contains_key(&statement.arguments[0]) {
|
||||||
let label_loc = labels.get(&statement.arguments[0]).unwrap();
|
let label_loc = labels.get(&statement.arguments[0]).unwrap();
|
||||||
current_statement = label_loc.clone();
|
current_statement = label_loc.clone();
|
||||||
|
@ -187,7 +176,7 @@ fn execute(program: Program) {
|
||||||
println!("Numerical type issues.");
|
println!("Numerical type issues.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "a" {
|
} else if statement.operator == Operator::ArithmeticAdd {
|
||||||
if vars.contains_key(&statement.arguments[0]) && vars.contains_key(&statement.arguments[1]) {
|
if vars.contains_key(&statement.arguments[0]) && vars.contains_key(&statement.arguments[1]) {
|
||||||
let value = vars.get(&statement.arguments[0]).unwrap();
|
let value = vars.get(&statement.arguments[0]).unwrap();
|
||||||
let value1 = vars.get(&statement.arguments[1]).unwrap();
|
let value1 = vars.get(&statement.arguments[1]).unwrap();
|
||||||
|
@ -204,7 +193,7 @@ fn execute(program: Program) {
|
||||||
println!("Missing variables.");
|
println!("Missing variables.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "s" {
|
} else if statement.operator == Operator::ArithmeticSubtract {
|
||||||
if vars.contains_key(&statement.arguments[0]) && vars.contains_key(&statement.arguments[1]) {
|
if vars.contains_key(&statement.arguments[0]) && vars.contains_key(&statement.arguments[1]) {
|
||||||
let value = vars.get(&statement.arguments[0]).unwrap();
|
let value = vars.get(&statement.arguments[0]).unwrap();
|
||||||
let value1 = vars.get(&statement.arguments[1]).unwrap();
|
let value1 = vars.get(&statement.arguments[1]).unwrap();
|
||||||
|
@ -221,7 +210,7 @@ fn execute(program: Program) {
|
||||||
println!("Missing variables.");
|
println!("Missing variables.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "m" {
|
} else if statement.operator == Operator::ArithmeticMultiply {
|
||||||
if vars.contains_key(&statement.arguments[0]) && vars.contains_key(&statement.arguments[1]) {
|
if vars.contains_key(&statement.arguments[0]) && vars.contains_key(&statement.arguments[1]) {
|
||||||
let value = vars.get(&statement.arguments[0]).unwrap();
|
let value = vars.get(&statement.arguments[0]).unwrap();
|
||||||
let value1 = vars.get(&statement.arguments[1]).unwrap();
|
let value1 = vars.get(&statement.arguments[1]).unwrap();
|
||||||
|
@ -238,7 +227,7 @@ fn execute(program: Program) {
|
||||||
println!("Missing variables.");
|
println!("Missing variables.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "d" {
|
} else if statement.operator == Operator::ArithmeticDivide {
|
||||||
if vars.contains_key(&statement.arguments[0]) && vars.contains_key(&statement.arguments[1]) {
|
if vars.contains_key(&statement.arguments[0]) && vars.contains_key(&statement.arguments[1]) {
|
||||||
let value = vars.get(&statement.arguments[0]).unwrap();
|
let value = vars.get(&statement.arguments[0]).unwrap();
|
||||||
let value1 = vars.get(&statement.arguments[1]).unwrap();
|
let value1 = vars.get(&statement.arguments[1]).unwrap();
|
||||||
|
@ -255,9 +244,9 @@ fn execute(program: Program) {
|
||||||
println!("Missing variables.");
|
println!("Missing variables.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "~" {
|
} else if statement.operator == Operator::ExplicitExit {
|
||||||
exit(0);
|
exit(0);
|
||||||
} else if statement.operator == "?" {
|
} else if statement.operator == Operator::TakeInput {
|
||||||
if vars.contains_key(&statement.arguments[0]) {
|
if vars.contains_key(&statement.arguments[0]) {
|
||||||
let value = vars.get(&statement.arguments[0]).unwrap();
|
let value = vars.get(&statement.arguments[0]).unwrap();
|
||||||
print!("{}", value);
|
print!("{}", value);
|
||||||
|
@ -268,7 +257,7 @@ fn execute(program: Program) {
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
io::stdin().read_line(&mut input).expect("Failed to read line!");
|
io::stdin().read_line(&mut input).expect("Failed to read line!");
|
||||||
vars.insert(statement.arguments[0].clone(), input.trim().to_string());
|
vars.insert(statement.arguments[0].clone(), input.trim().to_string());
|
||||||
} else if statement.operator == "&" {
|
} else if statement.operator == Operator::TypeCheck {
|
||||||
if vars.contains_key(&statement.arguments[0]) {
|
if vars.contains_key(&statement.arguments[0]) {
|
||||||
let value = vars.get(&statement.arguments[0]).unwrap();
|
let value = vars.get(&statement.arguments[0]).unwrap();
|
||||||
let binding = value.parse::<i64>();
|
let binding = value.parse::<i64>();
|
||||||
|
@ -280,7 +269,7 @@ fn execute(program: Program) {
|
||||||
} else {
|
} else {
|
||||||
vars.insert(statement.arguments[1].clone(), "-1".to_string());
|
vars.insert(statement.arguments[1].clone(), "-1".to_string());
|
||||||
}
|
}
|
||||||
} else if statement.operator == "%" {
|
} else if statement.operator == Operator::VariableClone {
|
||||||
if vars.contains_key(&statement.arguments[0]) {
|
if vars.contains_key(&statement.arguments[0]) {
|
||||||
let value = vars.get(&statement.arguments[0]).unwrap();
|
let value = vars.get(&statement.arguments[0]).unwrap();
|
||||||
vars.insert(statement.arguments[1].clone(), value.clone());
|
vars.insert(statement.arguments[1].clone(), value.clone());
|
||||||
|
@ -288,11 +277,11 @@ fn execute(program: Program) {
|
||||||
println!("Missing variable on clone.");
|
println!("Missing variable on clone.");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
} else if statement.operator == "$" {
|
} else if statement.operator == Operator::VariableDrop {
|
||||||
vars.remove(&statement.arguments[0]);
|
vars.remove(&statement.arguments[0]);
|
||||||
} else if statement.operator == "#" {
|
} else if statement.operator == Operator::StackPush {
|
||||||
stack.push(current_statement);
|
stack.push(current_statement);
|
||||||
} else if statement.operator == "|" {
|
} else if statement.operator == Operator::Return {
|
||||||
current_statement = stack.pop().expect("Stack underflow.");
|
current_statement = stack.pop().expect("Stack underflow.");
|
||||||
current_statement = current_statement + 1;
|
current_statement = current_statement + 1;
|
||||||
}
|
}
|
||||||
|
@ -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