new compiler

This commit is contained in:
2024-07-11 14:15:31 +02:00
parent 58af9cdd95
commit f4759f01c8
4 changed files with 163 additions and 47 deletions
+19 -1
View File
@@ -22,15 +22,33 @@ fn main() {
.short('o')
.long("output")
.takes_value(true)
.help("Specifies the output executable file name"),
.help("Specifies the output binary file name"),
)
.arg(
Arg::with_name("build")
.short('b')
.long("build")
.help("Puts the rust files in the build directory"),
)
.arg(
Arg::with_name("stdio")
.short('s')
.long("stdio")
.help("LSP Mode"),
)
.get_matches();
if matches.is_present("stdio") {
println!("stdio mode!");
} else {
let file = matches.value_of("file").unwrap().to_string();
let output = matches.value_of("output").unwrap_or("out").to_string();
if let Ok(_) = fs::create_dir("build") {}
let ecode = transpile(file, "main.rs".to_string(), true);
compile_rust(output);
if !matches.is_present("build") {
fs::remove_dir_all("build").expect("Error removing build");
}
process::exit(ecode as i32);
}
}
+92 -17
View File
@@ -1,10 +1,33 @@
use std::usize;
use once_cell::sync::Lazy;
use regex::Regex;
use crate::{
transpiler::{State, Transpiler},
utils::{Problem, ProblemCap, ProblemType, Variables},
};
pub struct Node {
pub regex_pattern: Lazy<Regex>,
pub token: u32,
}
const NODES: [Node; 3] = [
Node {
token: 1,
regex_pattern: Lazy::new(|| Regex::new(r"^(0(x|X)\d+|\d+)").unwrap()),
},
Node {
token: 2,
regex_pattern: Lazy::new(|| Regex::new(r"^[.:_a-zA-Z][a-zA-Z0-9_.:]*").unwrap()),
},
Node {
token: 5,
regex_pattern: Lazy::new(|| Regex::new(r"^(\;|\!|\=)").unwrap()),
},
];
#[derive(Clone, Debug)]
#[allow(dead_code)]
pub enum Token {
@@ -15,6 +38,8 @@ pub enum Token {
Identifier(String, State),
Curly(String, State),
Round(String, State),
Operator(String, State),
String(String, State),
// Square(String),
}
@@ -27,6 +52,8 @@ pub fn extract_values(token: Token) -> (u8, String, State) {
Token::DKeyword(x, state) => (4, x, state),
Token::SKeyword(x, state) => (5, x, state),
Token::Keyword(x, state) => (6, x, state),
Token::Operator(x, state) => (7, x, state),
Token::String(x, state) => (8, x, state),
}
}
@@ -72,10 +99,30 @@ pub fn get_token(v: String, t: u32, state: State) -> Token {
},
3 => Token::Round(v, state),
4 => Token::Curly(v, state),
5 => Token::Operator(v, state),
6 => Token::String(v, state),
_ => Token::Number(String::from(""), state),
}
}
pub fn tokenzie_regex(code: String, state: &mut State) -> (u32, String) {
let mut token = (0, String::new());
if !code.is_empty() {
for node in &NODES {
if let Some(caps) = node.regex_pattern.captures(&code) {
token.0 = node.token;
token.1 = caps[0].to_string();
state.column += token.1.len() as u32;
if token.1.contains("\n") {
state.column = 0;
state.line += token.1.chars().filter(|c| *c == '\n').count() as u32;
}
}
}
}
token
}
pub fn tokenize(code: String, state: &mut State, root: &mut Transpiler) -> Vec<Token> {
let mut code = code;
code += " ";
@@ -91,7 +138,8 @@ pub fn tokenize(code: String, state: &mut State, root: &mut Transpiler) -> Vec<T
while !code.is_empty() {
if let Some(c) = code.chars().next() {
code.remove(0);
let mut tval = c;
let tc = c.to_string();
let mut tval = tc.as_str();
let mut t: u32 = 0;
let mut ignore = false;
state.column += 1;
@@ -127,13 +175,13 @@ pub fn tokenize(code: String, state: &mut State, root: &mut Transpiler) -> Vec<T
}
}
'{' => {
if stoken.0 == 1 {
if stoken.0 == 2 {
stoken.1 += 1;
token_value += c.to_string().as_str();
}
}
'}' => {
if stoken.0 == 1 {
if stoken.0 == 2 {
stoken.1 -= 1;
if stoken.1 == 0 {
stoken.0 = 0;
@@ -149,20 +197,35 @@ pub fn tokenize(code: String, state: &mut State, root: &mut Transpiler) -> Vec<T
}
}
}
'"' => {
token_value += c.to_string().as_str();
if stoken.0 == 3 {
stoken.1 -= 1;
if stoken.1 == 0 {
stoken.0 = 0;
tokens.push(get_token(
token_value.clone(),
token_type,
token_state.clone(),
));
token_type = 0;
token_value = String::new();
}
}
}
'\\' => {
token_value += c.to_string().as_str();
token_value += code
.chars()
.next()
.expect("Error expected a char for \\")
.to_string()
.as_str();
}
_ => token_value += c.to_string().as_str(),
}
} else {
match c {
'0'..='9' => {
if token_type == 2 {
t = 2;
} else {
t = 1;
}
}
'a'..='z' | 'A'..='Z' => {
t = 2;
}
'\t' | ' ' => {
ignore = true;
}
@@ -174,22 +237,34 @@ pub fn tokenize(code: String, state: &mut State, root: &mut Transpiler) -> Vec<T
'(' => {
stoken.0 = 1;
stoken.1 = 1;
tval = ' ';
tval = " ";
t = 3;
}
'{' => {
stoken.0 = 2;
stoken.1 = 1;
tval = ' ';
tval = " ";
t = 4;
}
'"' => {
stoken.0 = 3;
stoken.1 = 1;
t = 6;
ignore = true;
}
x => {
ignore = true;
let vals = tokenzie_regex(format!("{}{}", c, code.clone()), state);
if vals.0 != 0 {
tokens.push(get_token(vals.1.clone(), vals.0, state.clone()));
code.drain(0..vals.1.len() - 1);
} else {
root.problems.push(ProblemCap::Error(Problem {
problem_msg: format!("Invalid character '{}'", x,),
problem_msg: format!("Invalid syntax '{}'", x,),
problem_type: ProblemType::SyntaxError,
state: state.clone(),
}));
ignore = true;
}
}
}
if token_type != t && token_type != 0 {
+8 -3
View File
@@ -106,10 +106,15 @@ impl Transpiler {
res += "}";
}
Ast::Single(x) => {
println!("{:?}", x);
let vals = extract_values(x);
if vals.0 == 1 {
println!("{:?}", vals);
res += vars.get_var(vals.1, self, vals.2).as_str();
match vals.0 {
2 => res += vars.get_var(vals.1, self, vals.2).as_str(),
3 => res += format!("({})", vals.1).as_str(),
8 => res += vals.1.as_str(),
_ => {
res += vals.1.as_str();
}
}
}
}
+21 -3
View File
@@ -51,7 +51,8 @@ pub struct Variables {
impl Variables {
pub fn new() -> Variables {
Variables {
vars: HashMap::from([(
vars: HashMap::from([
(
"void".to_string(),
Variable {
vtype: VariableType::Keyword,
@@ -66,7 +67,24 @@ impl Variables {
},
rname: "".to_string(),
},
)]),
),
(
"println".to_string(),
Variable {
vtype: VariableType::Keyword,
desc: "".to_string(),
state: State {
line: 0,
column: 0,
file: None,
},
params: Variables {
vars: HashMap::new(),
},
rname: "println".to_string(),
},
),
]),
}
}
pub fn new_var(&mut self, name: String, state: State, desc: String) -> String {
@@ -173,7 +191,7 @@ impl Variables {
} else {
root.problems.push(ProblemCap::Error(Problem {
problem_type: ProblemType::VariableNotFound,
problem_msg: format!("Variable '{}' doesn't exist", &name),
problem_msg: format!("'{}' doesn't exist", &name),
state: state,
}));
return name;