mclangc/src/preprocessor.rs

273 lines
10 KiB
Rust
Raw Normal View History

2023-03-20 11:39:04 +00:00
use std::collections::HashMap;
2023-04-01 10:20:35 +00:00
use std::path::{PathBuf, Path};
2023-03-20 11:39:04 +00:00
use color_eyre::Result;
use eyre::eyre;
use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType};
2023-03-20 12:36:38 +00:00
use crate::lexer::lex;
2023-04-01 13:54:02 +00:00
use crate::precompiler::precompile;
use crate::{lerror, lnote, Args, warn, linfo};
2023-03-20 11:39:04 +00:00
use crate::parser::lookup_word;
#[derive(Debug)]
pub struct Macro {
pub loc: Loc,
pub tokens: Vec<Token>
}
2023-04-01 13:54:02 +00:00
type Macros = HashMap<String, Macro>;
type Memories = HashMap<String, usize>;
2023-04-01 14:49:41 +00:00
pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<(Vec<Token>, Macros)>{
2023-03-20 11:39:04 +00:00
2023-04-01 13:54:02 +00:00
let mut program: Vec<Token> = Vec::new();
let mut macros: Macros = HashMap::new();
let mut memories: Memories = HashMap::new();
2023-03-21 18:12:24 +00:00
let mut rtokens = tokens;
2023-03-20 11:39:04 +00:00
rtokens.reverse();
2023-03-21 18:12:24 +00:00
while !rtokens.is_empty() {
2023-04-01 13:54:02 +00:00
let mut token = rtokens.pop().unwrap();
2023-03-20 11:39:04 +00:00
2023-03-21 18:12:24 +00:00
let op_type = lookup_word(&token.text, &token.loc());
2023-03-20 11:39:04 +00:00
match token.clone() {
_ if op_type == OpType::Keyword(KeywordType::Macro) => {
2023-03-21 18:12:24 +00:00
if rtokens.is_empty(){
2023-03-20 11:39:04 +00:00
lerror!(&token.loc(), "Macro name not found, expected {} but found nothing", TokenType::Word.human());
return Err(eyre!(""));
}
let macro_name = rtokens.pop().unwrap();
if macro_name.typ != TokenType::Word {
lerror!(&macro_name.loc(), "Bad macro name, expected {} but found {}", TokenType::Word.human(), macro_name.typ.human());
return Err(eyre!(""));
}
2023-03-21 18:12:24 +00:00
let word = lookup_word(&macro_name.text, &macro_name.loc());
if word != OpType::Instruction(InstructionType::None) {
2023-03-20 11:39:04 +00:00
lerror!(&macro_name.loc(), "Macro name cannot be a built in word, got '{}'", word.human());
return Err(eyre!(""));
}
2023-03-21 18:12:24 +00:00
if macros.get(&macro_name.text.clone()).is_some() && crate::constants::ALLOW_MACRO_REDEFINITION {
lerror!(&macro_name.loc(), "Macro redefinition is not allowed");
lnote!(&macros.get(&macro_name.text).unwrap().loc, "First definition here");
return Err(eyre!(""));
2023-03-20 11:39:04 +00:00
}
let mut macr = Macro{ loc: macro_name.loc(), tokens: Vec::new() };
2023-04-01 14:49:41 +00:00
let mut reprocess = false;
2023-03-20 11:39:04 +00:00
let mut depth = 0;
2023-03-21 18:12:24 +00:00
while !rtokens.is_empty() {
2023-03-20 11:39:04 +00:00
let t = rtokens.pop().unwrap();
2023-03-21 18:12:24 +00:00
let typ = lookup_word(&t.text, &t.loc());
if typ == OpType::Keyword(KeywordType::End) && depth == 0 {
2023-03-20 11:39:04 +00:00
break;
} else if typ == OpType::Keyword(KeywordType::End) && depth != 0 {
2023-03-20 11:39:04 +00:00
depth -= 1;
macr.tokens.push(t);
2023-04-01 14:49:41 +00:00
} else if typ == OpType::Keyword(KeywordType::If) ||
typ == OpType::Keyword(KeywordType::Do) {
macr.tokens.push(t);
depth += 1;
} else if typ == OpType::Keyword(KeywordType::Macro) {
reprocess = true;
2023-03-21 18:12:24 +00:00
macr.tokens.push(t);
depth += 1;
2023-03-20 11:39:04 +00:00
} else {
2023-03-21 18:12:24 +00:00
macr.tokens.push(t);
2023-03-20 11:39:04 +00:00
}
}
2023-04-01 14:49:41 +00:00
if reprocess {
(macr.tokens, macros) = preprocess(macr.tokens, args)?;
}
2023-03-20 11:39:04 +00:00
macros.insert(macro_name.text, macr);
}
_ if op_type == OpType::Keyword(KeywordType::Include) => {
2023-03-21 18:12:24 +00:00
if rtokens.is_empty() {
2023-03-20 12:36:38 +00:00
lerror!(&token.loc(), "Include path not found, expected {} but found nothing", TokenType::String.human());
return Err(eyre!(""));
}
let include_path = rtokens.pop().unwrap();
if include_path.typ != TokenType::String {
lerror!(&include_path.loc(), "Bad include path, expected {} but found {}", TokenType::String.human(), include_path.typ.human());
return Err(eyre!(""));
}
let mut in_paths = args.include.clone();
2023-03-21 18:12:24 +00:00
in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| (*f).to_string()).collect::<Vec<String>>());
2023-03-20 12:36:38 +00:00
let mut include_code = String::new();
2023-04-01 10:20:35 +00:00
if include_path.text.chars().collect::<Vec<char>>()[0] == '.' {
let p = Path::new(include_path.file.as_str());
let p = p.parent().unwrap();
let p = p.join(&include_path.text);
include_code = std::fs::read_to_string(p)?;
} else {
for path in in_paths {
let p = PathBuf::from(path);
let p = p.join(&include_path.text);
if p.exists() {
include_code = std::fs::read_to_string(p)?;
}
2023-03-20 12:36:38 +00:00
}
}
if include_code.is_empty() {
2023-04-01 10:20:35 +00:00
lerror!(&include_path.loc(), "Include file in path '{}' was not found or is empty", include_path.text);
2023-03-20 12:36:38 +00:00
return Err(eyre!(""));
}
2023-03-21 18:12:24 +00:00
let mut code = lex(&include_code, &include_path.text, args, false)?;
2023-03-20 12:36:38 +00:00
code.reverse();
rtokens.append(&mut code);
2023-04-01 13:54:02 +00:00
}
_ if op_type == OpType::Keyword(KeywordType::Memory) => {
if rtokens.is_empty() {
lerror!(&token.loc(), "Memory name not found, expected {} but found nothing", TokenType::String.human());
return Err(eyre!(""));
}
let memory_name = rtokens.pop().unwrap();
if memory_name.typ != TokenType::Word {
lerror!(&memory_name.loc(), "Bad memory name, expected {} but found {}", TokenType::Word.human(), memory_name.typ.human());
return Err(eyre!(""));
}
if macros.get(&memory_name.text).is_some() {
lerror!(&memory_name.loc(), "Memory name cannot replace macro name, got {}", memory_name.text);
let m = macros.get(&memory_name.text).unwrap();
linfo!(&m.loc, "Macro found here");
return Err(eyre!(""));
}
let mut code: Vec<Token> = Vec::new();
let mut depth = 0;
while !rtokens.is_empty() {
let t = rtokens.pop().unwrap();
let typ = lookup_word(&t.text, &t.loc());
if typ == OpType::Keyword(KeywordType::End) && depth == 0 {
break;
} else if typ == OpType::Keyword(KeywordType::End) && depth != 0 {
depth -= 1;
code.push(t);
} else if typ == OpType::Keyword(KeywordType::If) || typ == OpType::Keyword(KeywordType::Do) {
code.push(t);
depth += 1;
} else {
code.push(t);
}
}
let res = precompile(&code)?;
if res.len() != 1 {
lerror!(&token.loc(), "Expected 1 number, got {:?}", res);
return Err(eyre!(""));
}
token.value = Some(res[0]);
token.addr = Some(memories.len());
program.push(token);
memories.insert(memory_name.text, memories.len());
2023-03-20 12:36:38 +00:00
}
2023-03-20 11:39:04 +00:00
_ => {
program.push(token);
}
}
}
2023-03-20 14:13:34 +00:00
//* Feel free to fix this horrifying shit
//* i wanna kms
let mut times = 0;
while program.iter().map(|f| {
2023-04-01 13:54:02 +00:00
if f.typ == TokenType::Word && f.op_typ != InstructionType::MemUse {
2023-03-21 18:12:24 +00:00
lookup_word(&f.text, &f.loc())
2023-03-20 14:13:34 +00:00
} else {
OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works
2023-03-20 14:13:34 +00:00
}
}).collect::<Vec<OpType>>().contains(&OpType::Instruction(InstructionType::None)){
2023-03-20 14:13:34 +00:00
if times >= 50 {
warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it");
break
}
2023-04-01 13:54:02 +00:00
program = expand(program, &macros, &memories)?;
2023-03-20 14:13:34 +00:00
times += 1;
}
2023-03-20 11:39:04 +00:00
2023-04-01 14:49:41 +00:00
Ok((program, macros))
2023-03-20 11:39:04 +00:00
}
2023-04-01 13:54:02 +00:00
pub fn expand(tokens: Vec<Token>, macros: &Macros, mems: &Memories) -> Result<Vec<Token>> {
2023-03-20 11:39:04 +00:00
let mut program: Vec<Token> = Vec::new();
2023-04-01 14:49:41 +00:00
let mut rtokens = tokens.clone();
2023-03-20 11:39:04 +00:00
rtokens.reverse();
2023-03-21 18:12:24 +00:00
while !rtokens.is_empty() {
2023-03-20 11:39:04 +00:00
let op = rtokens.pop().unwrap();
2023-03-21 18:12:24 +00:00
let op_type = lookup_word(&op.text, &op.loc());
2023-03-20 11:39:04 +00:00
if op.typ == TokenType::Word {
match op_type {
OpType::Instruction(InstructionType::None) => {
2023-03-20 11:39:04 +00:00
let m = macros.get(&op.text);
2023-04-01 13:54:02 +00:00
let mem = mems.get(&op.text);
if let Some(m) = m {
2023-04-01 14:49:41 +00:00
// println!("{:#?}", macros);
let mut toks = m.tokens.clone();
// if toks.iter().map(|t| {
// let w = lookup_word(&t.text, &t.loc());
// w == OpType::Keyword(KeywordType::Macro)
// }).collect::<Vec<bool>>().contains(&true) {
// println!("yas");
// toks = preprocess(toks, args)?;
// }
program.append(&mut toks);
// println!("{:?}", program);
2023-04-01 13:54:02 +00:00
} else
if let Some(mem) = mem {
let mut t = op;
t.addr = Some(*mem);
t.op_typ = InstructionType::MemUse;
program.push(t);
}
else {
2023-03-20 11:39:04 +00:00
lerror!(&op.loc(), "Unknown word '{}'", op.text.clone());
return Err(eyre!(""));
}
}
_ => {
program.push(op);
}
}
} else {
program.push(op);
}
}
Ok(program)
}