diff --git a/.gitignore b/.gitignore index 388364e..281acbf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ /target -/a \ No newline at end of file +/a + +test +test.nasm +test.o \ No newline at end of file diff --git a/src/compile/linux_x86_64.rs b/src/compile/linux_x86_64.rs index c4dea5d..098d1b5 100644 --- a/src/compile/linux_x86_64.rs +++ b/src/compile/linux_x86_64.rs @@ -26,7 +26,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ let file = fs::File::create(&of_a)?; let mut writer = BufWriter::new(&file); - + let mut memories: Vec<(usize, usize)> = Vec::new(); // println!("{}", tokens.len()); let mut strings: Vec = Vec::new(); @@ -373,6 +373,11 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ writeln!(writer, " push rax")?; ti += 1; }, + InstructionType::MemUse => { + writeln!(writer, " ;; -- MemUse")?; + writeln!(writer, " push mem_{}", token.addr.unwrap())?; + ti += 1; + }, InstructionType::None => unreachable!(), InstructionType::CastBool => ti += 1, InstructionType::CastPtr => ti += 1, @@ -415,6 +420,10 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ } ti += 1; }, + KeywordType::Memory => { + memories.push((token.addr.unwrap(), token.value)); + ti += 1; + } KeywordType::Macro | KeywordType::Include => unreachable!() @@ -432,9 +441,12 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result{ let s_list = s_chars.join(","); writeln!(writer, " str_{}: db {} ; {}", i, s_list, s.escape_default())?; } - + writeln!(writer, "segment .bss")?; - writeln!(writer, "mem: resb {}", crate::compile::MEM_SZ)?; + for (_, s) in memories.iter().enumerate() { + writeln!(writer, " mem_{}: resb {}", s.0, s.1)?; + } + writeln!(writer, " mem: resb {}", crate::compile::MEM_SZ)?; writer.flush()?; linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?; diff --git a/src/constants.rs b/src/constants.rs index 9cd7c91..99111d5 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -4,7 +4,7 @@ pub const ALLOW_MACRO_REDEFINITION: bool = true; #[derive(Debug, Clone, PartialEq)] pub enum InstructionType { - + // stack PushInt, PushStr, @@ -30,13 +30,13 @@ pub enum InstructionType { Shl, // << DivMod, // / Mul, - - + + // mem Mem, Load8, Store8, - + // syscalls Syscall0, Syscall1, @@ -48,8 +48,9 @@ pub enum InstructionType { CastBool, CastPtr, - CastInt, + CastInt, + MemUse, None // Used for macros and any other non built in word definitions } @@ -62,6 +63,7 @@ pub enum KeywordType { Do, Macro, Include, + Memory } #[derive(Debug, Clone, PartialEq)] @@ -77,7 +79,7 @@ pub struct Operator{ pub text: String, //? only used for OpType::PushStr pub addr: Option, //? only used for OpType::PushStr pub jmp: usize, - pub loc: (String, usize, usize) + pub loc: Loc } impl Operator { @@ -91,55 +93,71 @@ impl Operator { loc: (file, row, col) } } - + pub fn set_addr(mut self, addr: usize) -> Self { + self.addr = Some(addr); + self + } + } impl OpType { pub fn human(&self) -> String { - match *self { - OpType::Instruction(InstructionType::PushInt) => "Number", - OpType::Instruction(InstructionType::PushStr) => "String", - OpType::Instruction(InstructionType::Print) => "print", - OpType::Instruction(InstructionType::Dup) => "dup", - OpType::Instruction(InstructionType::Drop) => "drop", - OpType::Instruction(InstructionType::Rot) => "rot", - OpType::Instruction(InstructionType::Over) => "over", - OpType::Instruction(InstructionType::Swap) => "swap", - OpType::Instruction(InstructionType::Plus) => "+", - OpType::Instruction(InstructionType::Minus) => "-", - OpType::Instruction(InstructionType::Equals) => "=", - OpType::Instruction(InstructionType::Gt) => ">", - OpType::Instruction(InstructionType::Lt) => "<", - OpType::Instruction(InstructionType::NotEquals) => "!=", - OpType::Instruction(InstructionType::Le) => "<=", - OpType::Instruction(InstructionType::Ge) => ">=", - OpType::Instruction(InstructionType::Band) => "band", - OpType::Instruction(InstructionType::Bor) => "bor", - OpType::Instruction(InstructionType::Shr) => "shr", - OpType::Instruction(InstructionType::Shl) => "shl", - OpType::Instruction(InstructionType::DivMod) => "divmod", - OpType::Instruction(InstructionType::Mul) => "*", - OpType::Keyword(KeywordType::If) => "if", - OpType::Keyword(KeywordType::Else) => "else", - OpType::Keyword(KeywordType::End) => "end", - OpType::Keyword(KeywordType::While) => "while", - OpType::Keyword(KeywordType::Do) => "do", - OpType::Keyword(KeywordType::Macro) => "macro", - OpType::Keyword(KeywordType::Include) => "include", - OpType::Instruction(InstructionType::Mem) => "mem", - OpType::Instruction(InstructionType::Load8) => "!8", - OpType::Instruction(InstructionType::Store8) => "@8", - OpType::Instruction(InstructionType::Syscall0) => "syscall0", - OpType::Instruction(InstructionType::Syscall1) => "syscall1", - OpType::Instruction(InstructionType::Syscall2) => "syscall2", - OpType::Instruction(InstructionType::Syscall3) => "syscall3", - OpType::Instruction(InstructionType::Syscall4) => "syscall4", - OpType::Instruction(InstructionType::Syscall5) => "syscall5", - OpType::Instruction(InstructionType::Syscall6) => "syscall6", - OpType::Instruction(InstructionType::CastBool) => "cast(bool", - OpType::Instruction(InstructionType::CastPtr) => "cast(ptr)", - OpType::Instruction(InstructionType::CastInt) => "cast(int)", - OpType::Instruction(InstructionType::None) => "None", + match (*self).clone() { + OpType::Instruction(instruction) => { + match instruction { + + InstructionType::PushInt => "Number", + InstructionType::PushStr => "String", + InstructionType::Print => "print", + InstructionType::Dup => "dup", + InstructionType::Drop => "drop", + InstructionType::Rot => "rot", + InstructionType::Over => "over", + InstructionType::Swap => "swap", + InstructionType::Plus => "+", + InstructionType::Minus => "-", + InstructionType::Equals => "=", + InstructionType::Gt => ">", + InstructionType::Lt => "<", + InstructionType::NotEquals => "!=", + InstructionType::Le => "<=", + InstructionType::Ge => ">=", + InstructionType::Band => "band", + InstructionType::Bor => "bor", + InstructionType::Shr => "shr", + InstructionType::Shl => "shl", + InstructionType::DivMod => "divmod", + InstructionType::Mul => "*", + InstructionType::Mem => "mem", + InstructionType::Load8 => "!8", + InstructionType::Store8 => "@8", + InstructionType::Syscall0 => "syscall0", + InstructionType::Syscall1 => "syscall1", + InstructionType::Syscall2 => "syscall2", + InstructionType::Syscall3 => "syscall3", + InstructionType::Syscall4 => "syscall4", + InstructionType::Syscall5 => "syscall5", + InstructionType::Syscall6 => "syscall6", + InstructionType::CastBool => "cast(bool", + InstructionType::CastPtr => "cast(ptr)", + InstructionType::CastInt => "cast(int)", + InstructionType::MemUse => "MemUse", + InstructionType::None => "None", + } + } + OpType::Keyword(keyword) => { + match keyword { + KeywordType::If => "if", + KeywordType::Else => "else", + KeywordType::End => "end", + KeywordType::While => "while", + KeywordType::Do => "do", + KeywordType::Macro => "macro", + KeywordType::Include => "include", + KeywordType::Memory => "memory" + } + } + }.to_string() } } @@ -150,7 +168,10 @@ pub struct Token { pub line: usize, pub col: usize, pub text: String, - pub typ: TokenType + pub typ: TokenType, + pub value: Option, //* only used for Memories + pub addr: Option, //* only used for Memories + pub op_typ: InstructionType //* only used for Memories } #[derive(Debug, Clone, PartialEq, Copy)] diff --git a/src/interpret/linux_x86_64/mod.rs b/src/interpret/linux_x86_64/mod.rs index 597d410..31b10ac 100644 --- a/src/interpret/linux_x86_64/mod.rs +++ b/src/interpret/linux_x86_64/mod.rs @@ -1,3 +1,5 @@ +use std::collections::HashMap; + use crate::{constants::{OpType, Loc, InstructionType, KeywordType}, lerror, error}; // use crate::util::logger; use color_eyre::Result; @@ -16,6 +18,8 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ let mut ti = 0; let mut mem: Vec = vec![0; crate::compile::MEM_SZ + crate::compile::STRING_SZ]; let mut string_idx = 0; + + let mut memories: HashMap = HashMap::new(); // for token in &tokens { // println!("{{typ: \"{:?}\", val: {}, jmp: {}}}", token.typ, token.value, token.jmp); @@ -100,6 +104,10 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ } InstructionType::Load8 => { let a = stack_pop(&mut stack, &pos)?; + if a > crate::compile::MEM_SZ { + lerror!(&token.loc, "Invalid memory address {a}"); + return Ok(1); + } let byte = mem[a]; stack.push(byte as usize); ti += 1; @@ -108,7 +116,12 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ InstructionType::Store8 => { let val = stack_pop(&mut stack, &pos)?; let addr = stack_pop(&mut stack, &pos)?; - + + if addr > crate::compile::MEM_SZ { + lerror!(&token.loc, "Invalid memory address {addr}"); + return Ok(1); + } + mem[addr] = (val & 0xFF) as u8; ti += 1; } @@ -246,39 +259,53 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result{ todo!(); // ti += 1; }, + InstructionType::MemUse => { + + let m = memories.get(&token.addr.unwrap()).unwrap(); + stack.push(*m); + ti += 1; + }, InstructionType::CastBool => ti += 1, InstructionType::CastPtr => ti += 1, InstructionType::CastInt => ti += 1, - InstructionType::None => unreachable!() + InstructionType::None => unreachable!(), } } - - // blocks - OpType::Keyword(KeywordType::If) => { - let a = stack_pop(&mut stack, &pos)?; - if a == 0 { - // println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp); - ti = token.jmp; - } else { - ti += 1; - } - }, - OpType::Keyword(KeywordType::Else) | OpType::Keyword(KeywordType::End) => { - ti = token.jmp; - } - OpType::Keyword(KeywordType::While) => { - ti += 1; - } - OpType::Keyword(KeywordType::Do) => { - let a = stack.pop().unwrap(); - if a == 0 { - ti = token.jmp; - } else { - ti += 1; + OpType::Keyword(k) => { + match k { + // blocks + KeywordType::If => { + let a = stack_pop(&mut stack, &pos)?; + if a == 0 { + // println!("If({ti}) => t: {:?} j: {}", tokens[token.jmp as usize].typ, token.jmp); + ti = token.jmp; + } else { + ti += 1; + } + }, + KeywordType::Else | KeywordType::End => { + ti = token.jmp; + } + KeywordType::While => { + ti += 1; + } + KeywordType::Do => { + let a = stack.pop().unwrap(); + if a == 0 { + ti = token.jmp; + } else { + ti += 1; + } + } + KeywordType::Memory => { + memories.insert(token.addr.unwrap(), token.value); + ti += 1; + }, + KeywordType::Macro | KeywordType::Include => unreachable!(), } } - | OpType::Keyword(KeywordType::Macro) | OpType::Keyword(KeywordType::Include) => unreachable!() + } } diff --git a/src/lexer.rs b/src/lexer.rs index 533a720..a1f41df 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -108,7 +108,10 @@ pub fn lex + std::marker::Copy>(code: &str, file: S, args: &Args line: row + 1, col, text: tok, - typ: tok_type + typ: tok_type, + value: None, + addr: None, + op_typ: crate::constants::InstructionType::None }; tokens.push(t); } diff --git a/src/main.rs b/src/main.rs index bbcb2d5..c85c814 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod parser; mod lexer; mod preprocessor; mod typechecker; +mod precompiler; use std::fs; @@ -17,6 +18,8 @@ pub const DEFAULT_INCLUDES: [&str;2] = [ "~/.mclang/include", ]; + + #[derive(Parser, Debug, Clone)] #[command(author, version, about, long_about = None)] pub struct Args { @@ -48,6 +51,9 @@ pub struct Args { #[arg(long, short='I')] include: Vec, + /// Unsafe mode, disables typechecking + #[arg(long="unsafe", default_value_t = false)] + unsaf: bool //#[arg(long, short='F')] //features: Vec, diff --git a/src/parser.rs b/src/parser.rs index e14b0b1..2e21f55 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -79,8 +79,13 @@ impl Parser { let pos = (token.file.clone(), token.line, token.col); match token.typ { TokenType::Word => { - let word_type = lookup_word(&token.text, &pos); - tokens.push(Operator::new(word_type, 0, token.text.clone(), token.file.clone(), token.line, token.col)); + let word_type = if token.op_typ == InstructionType::MemUse { + OpType::Instruction(InstructionType::MemUse) + } else { + lookup_word(&token.text, &pos) + }; + + tokens.push(Operator::new(word_type, token.value.unwrap_or(0), token.text.clone(), token.file.clone(), token.line, token.col).set_addr(token.addr.unwrap_or(0))); }, TokenType::Int => {// negative numbers not yet implemented tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.text.parse::()?, String::new(), token.file.clone(), token.line, token.col)); @@ -109,6 +114,10 @@ impl Parser { pub fn lookup_word>(s: &str, _pos: P) -> OpType { + let n = s.parse::(); + if let Ok(_) = n { + return OpType::Instruction(InstructionType::PushInt); + } match s { //stack "print" => OpType::Instruction(InstructionType::Print), @@ -135,20 +144,12 @@ pub fn lookup_word>(s: &str, _pos: P) -> OpType { "divmod" => OpType::Instruction(InstructionType::DivMod), "*" => OpType::Instruction(InstructionType::Mul), - // block - "if" => OpType::Keyword(KeywordType::If), - "else" => OpType::Keyword(KeywordType::Else), - "end" => OpType::Keyword(KeywordType::End), - "while" => OpType::Keyword(KeywordType::While), - "do" => OpType::Keyword(KeywordType::Do), - "macro" => OpType::Keyword(KeywordType::Macro), - "include" => OpType::Keyword(KeywordType::Include), - + // mem "mem" => OpType::Instruction(InstructionType::Mem), - "!8" => OpType::Instruction(InstructionType::Load8), - "@8" => OpType::Instruction(InstructionType::Store8), - + "load8" => OpType::Instruction(InstructionType::Load8), + "store8" => OpType::Instruction(InstructionType::Store8), + "syscall0" => OpType::Instruction(InstructionType::Syscall0), "syscall1" => OpType::Instruction(InstructionType::Syscall1), "syscall2" => OpType::Instruction(InstructionType::Syscall2), @@ -159,6 +160,15 @@ pub fn lookup_word>(s: &str, _pos: P) -> OpType { "cast(bool" => OpType::Instruction(InstructionType::CastBool), "cast(ptr)" => OpType::Instruction(InstructionType::CastPtr), "cast(int)" => OpType::Instruction(InstructionType::CastInt), + // block + "if" => OpType::Keyword(KeywordType::If), + "else" => OpType::Keyword(KeywordType::Else), + "end" => OpType::Keyword(KeywordType::End), + "while" => OpType::Keyword(KeywordType::While), + "do" => OpType::Keyword(KeywordType::Do), + "macro" => OpType::Keyword(KeywordType::Macro), + "include" => OpType::Keyword(KeywordType::Include), + "memory" => OpType::Keyword(KeywordType::Memory), _ => OpType::Instruction(InstructionType::None) } diff --git a/src/precompiler.rs b/src/precompiler.rs new file mode 100644 index 0000000..7b60624 --- /dev/null +++ b/src/precompiler.rs @@ -0,0 +1,154 @@ + +use color_eyre::Result; +use eyre::eyre; + +use crate::{constants::{Token, OpType, InstructionType, Loc}, parser::lookup_word, lerror}; + +fn stack_pop(stack: &mut Vec, loc: &Loc) -> Result { + if let Some(i) = stack.pop() { Ok(i) } else { + lerror!(&loc.clone(), "Stack underflow"); + Err(eyre!("Stack underflow")) + } +} + +pub fn precompile(tokens: &Vec) -> Result>{ + + let mut stack: Vec = Vec::new(); + + for token in tokens.iter() { + let typ = lookup_word(&token.text, &token.loc()); + match typ { + OpType::Instruction(i) => { + let loc = token.loc(); + match i { + InstructionType::PushInt => { + if let Ok(i) = token.text.parse::() { + stack.push(i); + } else { + lerror!(&token.loc(), "Bad number"); + return Err(eyre!("")); + } + }, + InstructionType::Plus => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(b + a); + }, + InstructionType::Minus => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(b - a); + }, + InstructionType::Equals => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(usize::from(b == a)); + }, + InstructionType::Gt => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(usize::from(b > a)); + }, + InstructionType::Lt => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(usize::from(b < a)); + }, + InstructionType::NotEquals => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(usize::from(b != a)); + }, + InstructionType::Ge => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(usize::from(b >= a)); + }, + InstructionType::Le => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(usize::from(b <= a)); + }, + + InstructionType::Band => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(a & b); + } + + InstructionType::Bor => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(a | b); + } + + InstructionType::Shr => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(b >> a); + } + + InstructionType::Shl => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(b << a); + } + + InstructionType::DivMod => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(b / a); + stack.push(b % a); + } + InstructionType::Mul => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(b * a); + } + InstructionType::Drop => { + stack.pop(); + }, + InstructionType::Dup => { + let a = stack_pop(&mut stack, &loc)?; + stack.push(a); + stack.push(a); + }, + + InstructionType::Rot => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + let c = stack_pop(&mut stack, &loc)?; + stack.push(b); + stack.push(a); + stack.push(c); + } + InstructionType::Swap => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(a); + stack.push(b); + } + InstructionType::Over => { + let a = stack_pop(&mut stack, &loc)?; + let b = stack_pop(&mut stack, &loc)?; + stack.push(b); + stack.push(a); + stack.push(b); + } + _ => { + lerror!(&token.loc(), "Unsupported precompiler instruction {:?}", i); + dbg!(tokens); + return Err(eyre!("")); + } + } + } + _ => { + lerror!(&token.loc(), "Unsupported precompiler keyword {:?}", typ); + dbg!(tokens); + return Err(eyre!("")); + } + } + } + + Ok(stack) +} \ No newline at end of file diff --git a/src/preprocessor.rs b/src/preprocessor.rs index 848f06e..cdc6c89 100644 --- a/src/preprocessor.rs +++ b/src/preprocessor.rs @@ -6,7 +6,8 @@ use eyre::eyre; use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType}; use crate::lexer::lex; -use crate::{lerror, lnote, Args, warn}; +use crate::precompiler::precompile; +use crate::{lerror, lnote, Args, warn, linfo}; use crate::parser::lookup_word; #[derive(Debug)] @@ -15,14 +16,20 @@ pub struct Macro { pub tokens: Vec } +type Macros = HashMap; +type Memories = HashMap; + pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ - let mut program: Vec = Vec::new(); - let mut macros: HashMap = HashMap::new(); + + let mut program: Vec = Vec::new(); + let mut macros: Macros = HashMap::new(); + let mut memories: Memories = HashMap::new(); + let mut rtokens = tokens; rtokens.reverse(); while !rtokens.is_empty() { - let token = rtokens.pop().unwrap(); + let mut token = rtokens.pop().unwrap(); let op_type = lookup_word(&token.text, &token.loc()); match token.clone() { @@ -66,7 +73,6 @@ pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ } else { macr.tokens.push(t); } - } @@ -120,6 +126,57 @@ pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ rtokens.append(&mut code); + } + _ 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 = 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()); + } _ => { program.push(token); @@ -131,7 +188,7 @@ pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ //* i wanna kms let mut times = 0; while program.iter().map(|f| { - if f.typ == TokenType::Word { + if f.typ == TokenType::Word && f.op_typ != InstructionType::MemUse { lookup_word(&f.text, &f.loc()) } else { OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works @@ -143,7 +200,7 @@ pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it"); break } - program = expand_macros(program, ¯os)?; + program = expand(program, ¯os, &memories)?; times += 1; } @@ -151,7 +208,7 @@ pub fn preprocess(tokens: Vec, args: &Args) -> Result>{ Ok(program) } -pub fn expand_macros(tokens: Vec, macros: &HashMap) -> Result> { +pub fn expand(tokens: Vec, macros: &Macros, mems: &Memories) -> Result> { let mut program: Vec = Vec::new(); let mut rtokens = tokens; @@ -164,11 +221,17 @@ pub fn expand_macros(tokens: Vec, macros: &HashMap) -> Res match op_type { OpType::Instruction(InstructionType::None) => { let m = macros.get(&op.text); - if m.is_some() { - if let Some(m) = m { - program.append(&mut m.tokens.clone()); - } - } else { + let mem = mems.get(&op.text); + if let Some(m) = m { + program.append(&mut m.tokens.clone()); + } else + if let Some(mem) = mem { + let mut t = op; + t.addr = Some(*mem); + t.op_typ = InstructionType::MemUse; + program.push(t); + } + else { lerror!(&op.loc(), "Unknown word '{}'", op.text.clone()); return Err(eyre!("")); } diff --git a/src/typechecker.rs b/src/typechecker.rs index 47597f9..c5e4302 100644 --- a/src/typechecker.rs +++ b/src/typechecker.rs @@ -1,9 +1,15 @@ -use crate::{constants::{Operator, Types, OpType, KeywordType, InstructionType}, Args, lerror}; +use crate::{constants::{Operator, Types, OpType, KeywordType, InstructionType}, Args, lerror, warn}; use color_eyre::Result; use eyre::eyre; pub fn typecheck(ops: &[Operator], args: &Args) -> Result>{ + if args.unsaf { + if !args.quiet { + warn!("Unsafe mode enabled, disabling typechecker, goodluck"); + } + return Ok(ops.to_vec()); + } let mut stack: Vec = Vec::new(); @@ -13,25 +19,17 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result>{ match keyword { KeywordType::If => { stack_pop(&mut stack, &op, &[Types::Bool])?; - }, - KeywordType::Else => { - - }, - KeywordType::End => { - - }, - KeywordType::While => { - }, KeywordType::Do => { stack_pop(&mut stack, &op, &[Types::Bool])?; }, - KeywordType::Macro => { - }, - KeywordType::Include => { - - }, + KeywordType::Else | + KeywordType::End | + KeywordType::While | + KeywordType::Macro | + KeywordType::Include | + KeywordType::Memory => (), } }, OpType::Instruction(instruction) => { @@ -218,6 +216,9 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result>{ stack_pop(&mut stack, &op, &[Types::Any])?; stack.push(Types::Int); }, + InstructionType::MemUse => { + stack.push(Types::Ptr); + }, InstructionType::None => {}, } }, diff --git a/test.mcl b/test.mcl index b8645c6..6f45b83 100644 --- a/test.mcl +++ b/test.mcl @@ -1,3 +1,6 @@ -include "./asd.mcl" +memory m 10 end -1 test \ No newline at end of file +m 69 store8 + + +m load8 print \ No newline at end of file