diff --git a/README.md b/README.md
index 72248c2..929a42b 100644
--- a/README.md
+++ b/README.md
@@ -7,11 +7,9 @@
Wyst is a programing language that has similar syntax to C and transpiles to Rust
-<<<<<<< HEAD
-# Re Write
-We are re-writing the parser and transpiler due to the messy code that is very hard to expand
-=======
+# Hello World
```c
+// main.wst
#include
int main() {
@@ -19,7 +17,11 @@ int main() {
return 0;
}
```
->>>>>>> 30ed01f (Update README.md)
+
+# Compile it
+```bash
+wyst main.wst -o
+```
# Alpha
We are on pure alpha. if you would like to contribute please open a new issue.
diff --git a/lib/stdio.rs b/lib/stdio.rs
new file mode 100644
index 0000000..2a7ac7d
--- /dev/null
+++ b/lib/stdio.rs
@@ -0,0 +1,6 @@
+#[macro_export]
+macro_rules! printf {
+ ($($arg:tt)*) => {
+ println!($($arg)*);
+ };
+}
\ No newline at end of file
diff --git a/src/compiler.rs b/src/compiler.rs
index d1d0945..c79f8ab 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -6,30 +6,29 @@ use crate::{
utils::{Problem, ProblemCap, ProblemType},
};
-pub fn transpile(input_file: String, output_file: String, is_main: bool) -> u8 {
+pub fn transpile_file(input_file: String, output_file: String, is_main: bool) -> u8 {
let mut ecode: u8 = 0;
let mut trsp = Transpiler {
..Default::default()
};
if let Ok(file_contents) = fs::read_to_string(input_file) {
- let output_code = trsp.transpile_code(file_contents, 0);
- println!("{output_code}");
+ let mut module_code = String::new();
+ let mut output_code = String::new();
+ match trsp.transpile_code(file_contents, 0) {
+ Ok(rcode) => output_code+=rcode.as_str(),
+ Err(e) => {ecode=1;println!("{e}")}
+ }
if is_main {
- // output_code += "fn main() {";
- // output_code += vars
- // .get_var(
- // "main".to_string(),
- // &mut trsp,
- // State {
- // line: 0,
- // column: 0,
- // file: None,
- // },
- // )
- // .as_str();
- // output_code += "();}";
+ for module in trsp.clone().mod_manager.modules {
+ module_code += "mod ";
+ module_code += module.rs_mod.as_str();
+ module_code += ";\n";
+ }
+ }
+ output_code = format!("{module_code}\n{output_code}");
+ if let Ok(_) = fs::write(Path::new("build").join(output_file), output_code) {
+ trsp.problems.append(&mut trsp.mod_manager.write());
}
- if let Ok(_) = fs::write(Path::new("build").join(output_file), output_code) {}
} else {
trsp.problems.push(ProblemCap::Error(Problem {
problem_msg: "File not found".to_string(),
@@ -69,11 +68,11 @@ pub fn compile_rust(exe_file: String) {
let output = Command::new("rustc")
.arg(Path::new("build").join("main.rs"))
.arg("-o")
- .arg(exe_file)
+ .arg(exe_file.clone())
.output()
.expect("Error compiling rust: ");
if &output.stderr.len() == &0 {
- println!("Compiled successfully");
+ println!("Compiled successfully: \x1b[34;4m{}", exe_file.clone());
} else {
println!("{}", str::from_utf8(&output.stderr).expect("Error encoding stderr"));
}
diff --git a/src/main.rs b/src/main.rs
index d61a7ea..cfaccb3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,11 +1,10 @@
use std::{fs, process};
-
mod compiler;
mod transpiler;
mod utils;
use clap::{App, Arg};
-use compiler::{compile_rust, transpile};
+use compiler::{compile_rust, transpile_file};
fn main() {
let matches = App::new("Wyst")
@@ -44,8 +43,10 @@ fn main() {
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);
+ let ecode = transpile_file(file, "main.rs".to_string(), true);
+ if ecode == 0 {
+ compile_rust(output);
+ }
if !matches.is_present("build") {
fs::remove_dir_all("build").expect("Error removing build");
}
diff --git a/src/transpiler.rs b/src/transpiler.rs
index 687552f..8718927 100644
--- a/src/transpiler.rs
+++ b/src/transpiler.rs
@@ -1,9 +1,9 @@
use pest::iterators::{Pair, Pairs};
-use crate::utils::{ProblemCap};
+use crate::utils::{ModManager, ProblemCap};
use serde::{Deserialize, Serialize};
// The Parser
-use pest::Parser;
+use pest::{Parser, error::Error};
use pest_derive::Parser;
#[derive(Parser)]
#[grammar = "wyst.pest"]
@@ -16,13 +16,16 @@ pub struct State {
pub file: Option,
}
-#[derive(Deserialize, Serialize, Debug, Clone)]
+#[derive(Debug, Clone)]
+#[allow(dead_code)]
pub struct Transpiler {
pub problems: Vec,
pub state: State,
pub inject: Inject,
+ pub mod_manager: ModManager,
}
-#[derive(Deserialize, Serialize, Debug, Clone)]
+#[derive(Debug, Clone)]
+#[allow(dead_code)]
pub struct Inject {
pub state: State,
pub inject: bool,
@@ -46,6 +49,7 @@ impl Default for Transpiler {
Transpiler {
inject: Inject::default(),
problems: Vec::new(),
+ mod_manager: ModManager::new(),
state: State {
line: 1,
column: 0,
@@ -75,7 +79,7 @@ impl Transpiler {
let tokens = to_indexable(pair.clone().into_inner());
match pair.as_rule() {
Rule::func_def => {
- res += format!("fn {}({}) -> {} {}", self.transpile(tokens[1].clone()),
+ res += format!("pub fn {}({}) -> {} {}\n", self.transpile(tokens[1].clone()),
self.transpile_pairs(tokens[2].clone().into_inner()).as_str(),
self.transpile(tokens[0].clone()),
self.transpile(tokens[3].clone())
@@ -92,16 +96,29 @@ impl Transpiler {
Rule::code_expr => {
res += &self.transpile_pairs(pair.clone().into_inner());
}
- //TODO: use LibManager to manage the includes
- Rule::include_global => {}
- Rule::include => {}
+
+ Rule::include_global => {
+ res += "#[allow(unused_imports)]\nuse ";
+ res += self.mod_manager.add(tokens[0].as_str().to_string(), true).as_str();
+ res += "::*;\n";
+ }
+ Rule::include => {
+ res += "#[allow(unused_imports)]\nuse ";
+ res += self.mod_manager.add(tokens[0].as_str().to_string(), false).as_str();
+ res += "::*;\n";
+ }
Rule::identifier => {
let ident = pair.as_str().trim();
- res+=match ident {
- "void" => {"()"}
- _ => {ident}
- };
+ if self.mod_manager.macros.contains(&ident.to_string()) {
+ res+=ident;
+ res+="!";
+ } else {
+ res+=match ident {
+ "void" => {"()"}
+ _ => {ident}
+ };
+ }
}
Rule::def_identifier => {
@@ -112,6 +129,26 @@ impl Transpiler {
};
}
+ Rule::call => {
+ res += " ";
+ res += self.transpile(tokens[0].clone()).as_str();
+ res += self.transpile(tokens[1].clone()).as_str();
+ }
+
+ Rule::round => {
+ res += "(";
+ res += self.transpile_pairs(pair.into_inner()).as_str();
+ res += ")";
+ }
+
+ Rule::expr => {
+ res += self.transpile_pairs(pair.into_inner()).as_str();
+ }
+
+ Rule::expr_ => {
+ res += self.transpile_pairs(pair.into_inner()).as_str();
+ }
+
_ => {
res += " ";
res += pair.as_str();
@@ -120,7 +157,7 @@ impl Transpiler {
}
res
}
- pub fn transpile_code(&mut self, code: String, indent: usize) -> String {
+ pub fn transpile_code(&mut self, code: String, indent: usize) -> Result> {
let mut res = String::new();
match WystParser::parse(Rule::top_expr, &code) {
Ok(parsed) => {
@@ -129,7 +166,7 @@ impl Transpiler {
}
}
Err(e) => {
- println!("{}", e);
+ return Err(e);
}
}
if indent > 0 {
@@ -140,6 +177,6 @@ impl Transpiler {
res += "\n";
res += " ".repeat((indent - 1) * 2).as_str();
}
- res
+ Ok(res)
}
}
diff --git a/src/utils.rs b/src/utils.rs
index 169095a..740fb1b 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -1,5 +1,9 @@
-use crate::transpiler::State;
+use std::fs;
+use std::path::Path;
+use crate::transpiler::{Rule, State, Transpiler, WystParser};
use serde::{Deserialize, Serialize};
+use dirs::home_dir;
+use pest::Parser;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ProblemType {
@@ -19,4 +23,104 @@ pub struct Problem {
pub problem_type: ProblemType,
pub problem_msg: String,
pub state: State,
+}
+
+#[derive(Debug, Clone)]
+pub struct Module {
+ pub rs_mod: String,
+ pub file_path: String,
+ pub code: String
+}
+
+#[derive(Debug, Clone)]
+pub struct ModManager {
+ pub modules: Vec,
+ pub macros: Vec
+}
+
+impl ModManager {
+ pub fn new() -> ModManager {
+ ModManager {modules: Vec::new(), macros: Vec::new()}
+ }
+ pub fn check(&mut self, path: String) -> Option {
+ for module in self.modules.clone() {
+ if module.file_path == path {
+ return Some(module);
+ }
+ }
+ None
+ }
+ pub fn add(&mut self, file_path: String, global: bool) -> String {
+ let mut problems: Vec = Vec::new();
+ let mod_name = format!("mod_{}", self.modules.len());
+ let home_dirpb = home_dir().unwrap();
+ let home_dir = home_dirpb.to_str().unwrap();
+ let mut file_path = file_path;
+ if global {
+ let mut tmp = Path::new(home_dir).join("wyst").join("lib").join(file_path.clone()).to_str().unwrap().to_string();
+ if !Path::new(&tmp).exists() {
+ tmp = Path::new("lib").join(file_path).to_str().unwrap().to_string();
+ }
+ file_path = tmp;
+ }
+ if let Some(modl) = self.check(file_path.clone()) {
+ return modl.rs_mod;
+ }
+ if let Ok(code) = fs::read_to_string(file_path.clone()) {
+ self.modules.push(Module { rs_mod: mod_name.clone(), file_path: file_path.clone(), code: code.clone() });
+ match file_path.rsplit_once('.').unwrap_or(("", "")).1 {
+ "rs" => {
+ match WystParser::parse(Rule::rust_code, &code) {
+ Ok(parsed) => {
+ for pair in parsed {
+ for p in pair.into_inner() {
+ if p.as_rule() == Rule::rust_macro_lint {
+ self.macros.push(p.into_inner().as_str().to_string());
+ }
+ }
+ }
+ }
+ Err(_) => {}
+ }
+ }
+ _ => {}
+ }
+ } else {
+ problems.push(ProblemCap::Error(Problem {
+ problem_msg: format!("File not found '{}'", file_path),
+ problem_type: ProblemType::FileNotFound,
+ state: State {
+ line: 0,
+ column: 0,
+ file: None,
+ },
+ }))
+ }
+ mod_name
+ }
+ pub fn write(&mut self) -> Vec {
+ let mut problems: Vec = Vec::new();
+ for module in self.modules.clone() {
+ let file_path = module.file_path;
+ match file_path.rsplit_once('.').unwrap_or(("", "")).1 {
+ "wst" => {
+ let mut trsp = Transpiler {
+ mod_manager: self.clone(),
+ ..Default::default()
+ };
+ let rust_code = trsp.transpile_code(module.code, 0).expect("");
+ fs::write(Path::new("build").join((module.rs_mod+".rs").as_str()), rust_code).expect("Error writing rust file: ");
+ problems.append(&mut trsp.problems);
+ self.modules = trsp.mod_manager.modules;
+ }
+
+ "rs" => {
+ fs::write(Path::new("build").join((module.rs_mod+".rs").as_str()), &module.code).unwrap()
+ }
+
+ _ => {}
+ }
+ }
+ problems
+ }
}
\ No newline at end of file
diff --git a/src/wyst.pest b/src/wyst.pest
index 6e1ddea..ff665ab 100644
--- a/src/wyst.pest
+++ b/src/wyst.pest
@@ -32,8 +32,15 @@ var_def_set = { var_def ~ "=" ~ expr }
var_set = { def_identifier ~ "=" ~ expr }
func_def = { def_identifier ~ identifier ~ round_def ~ curly }
-expr = {
- (identifier ~ round) |
+rust_macro_lint = { "macro_rules" ~ "!" ~ identifier }
+rust_code = { (rust_macro_lint | ANY)* }
+
+plus = {"+"}
+
+call = {identifier ~ round}
+
+expr_ = {
+ call |
round |
curly |
char |
@@ -45,11 +52,18 @@ expr = {
string
}
+expr = {
+ (expr_ ~ plus ~ expr_) |
+ expr_
+}
+
code_expr = {
- (var_def_set ~ semicolon) |
- (var_def ~ semicolon) |
- (var_set ~ semicolon) |
- (expr ~ semicolon)
+ (
+ var_def_set|
+ var_def |
+ var_set |
+ expr
+ ) ~ semicolon
}
top_expr = {