mod parser;
mod messages;
use pest::Parser;
use pest::iterators::Pair;
use hashbrown::HashMap;
use parser::*;
use messages::*;
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub enum MacroArgType {
Nut, Ident,
Text,
Number,
Block,
}
impl MacroArgType {
pub fn from_str(arg_type: &str) -> Option<Self> {
return Some(match arg_type.trim() {
"ident" => MacroArgType::Ident,
"text" => MacroArgType::Text,
"number" => MacroArgType::Number,
"block" => MacroArgType::Block,
_ => return None,
});
}
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Compiler<'a> {
pub consts: HashMap<String, u8>,
pub imports: Vec<String>,
pub functions: HashMap<String, (Vec<String>, Vec<Pair<'a, Rule>>)>,
pub macros: HashMap<String, (Vec<(String, MacroArgType)>, Vec<Pair<'a, Rule>>)>,
}
impl<'a> Compiler<'a> {
pub fn new() -> Self {
return Self {
consts: HashMap::new(),
imports: Vec::new(),
functions: HashMap::new(),
macros: HashMap::new(),
};
}
pub fn compile(&mut self, code: &'a str) -> Option<String> {
let mut bf: Vec<char> = Vec::new();
let ast = match BronoParser::parse(Rule::file, code) {
Ok(o) => o,
Err(_) => return None,
};
for (file_i, file) in ast.enumerate() {
for record in file.into_inner() {
match record.as_rule() {
Rule::k_const => {
let pairs: Vec<_> = record.into_inner().into_iter().collect();
let name = pairs.get(0).unwrap().as_str();
let value: u8 = pairs.get(1).unwrap().as_str().trim().parse().unwrap();
self.consts.insert(name.to_string(), value);
},
Rule::k_import => {
let pairs: Vec<_> = record.into_inner().into_iter().collect();
let library = pairs.get(0).unwrap().as_str();
self.imports.push(library.to_string());
},
Rule::k_fn => {
let pairs: Vec<_> = record.into_inner().into_iter().collect();
let name = pairs.get(0).unwrap().as_str();
let arguments_pre = pairs.get(1).unwrap().clone().into_inner();
let mut arguments: Vec<String> = Vec::new();
for i in arguments_pre {
arguments.push(i.as_str().to_string());
}
let block = pairs.get(2).unwrap().clone();
self.functions.insert(name.to_string(), (arguments, block.into_inner().into_iter().collect()));
},
Rule::k_macro => {
let pairs: Vec<_> = record.into_inner().into_iter().collect();
let name = pairs.get(0).unwrap().as_str();
let arguments_pre = pairs.get(1).unwrap().clone().into_inner();
let mut arguments: Vec<(String, MacroArgType)> = Vec::new();
let mut carg = "";
for (i, a) in arguments_pre.enumerate() {
if i & 1 == 0 {
carg = a.as_str();
}
else {
arguments.push((carg.to_string(), MacroArgType::from_str(a.as_str()).unwrap()));
}
}
let block = pairs.get(2).unwrap().clone();
self.macros.insert(name.to_string(), (arguments, block.into_inner().into_iter().collect()));
},
Rule::EOI => (),
_ => unreachable!(),
};
println!("");
}
if file_i > 0 {
panic!("There should only be one file, and one file only! Fix your shit!");
}
}
let file_name = "main.brono";
let main_func = match self.functions.get("main") {
Some(s) => s,
None => {
let message = Message::new(
"Missing main() function!",
MessageType::Error,
MessageLocation::File(file_name, MessageSpan::empty(), None),
);
message.print();
return None;
},
};
if main_func.0.len() != 0 {
let message = Message::new(
"main() function doesn't take any parameters! It is the program entry!",
MessageType::Error,
MessageLocation::File(file_name, MessageSpan::empty(), None),
);
message.print();
return None;
}
return Some(bf.into_iter().map(|x| x.to_string()).collect::<Vec<_>>().concat());
}
}