not working very well with std lib but working standalone ig

This commit is contained in:
MCorange
2023-04-11 16:24:52 +03:00
parent 9c84033d3f
commit 63636e1f83
19 changed files with 1115 additions and 741 deletions

View File

@@ -7,6 +7,8 @@ use super::commands::linux_x86_64_run;
pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
let debug = args.optimisation == "D";
let mut of_c = PathBuf::from(&args.out_file);
let (mut of_o, mut of_a) = if args.out_file == *crate::DEFAULT_OUT_FILE {
let of_o = PathBuf::from("/tmp/mclang_comp.o");
@@ -27,6 +29,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
let file = fs::File::create(&of_a)?;
let mut writer = BufWriter::new(&file);
let mut memories: Vec<(usize, usize)> = Vec::new();
let mut constants: Vec<(String, Option<usize>, Option<String>)> = Vec::new();
// println!("{}", tokens.len());
let mut strings: Vec<String> = Vec::new();
@@ -68,7 +71,8 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
writeln!(writer, " ret")?;
writeln!(writer, "global _start")?;
writeln!(writer, "_start:")?;
writeln!(writer, "_start:")?;
writeln!(writer, " lea rbp, [rel ret_stack]")?;
writeln!(writer, " call func_main")?;
writeln!(writer, " jmp end")?;
@@ -76,41 +80,73 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
let mut ti = 0;
while ti < tokens.len() {
let token = &tokens[ti];
println!("{:?}", token);
writeln!(writer, "addr_{ti}:")?;
// println!("{:?}", token);
if debug {
writeln!(writer, "addr_{ti}:")?;
if token.typ == OpType::Instruction(InstructionType::PushInt) {
writeln!(writer, " ;; -- {:?} {}", token.typ, token.value)?;
} else
if token.typ == OpType::Instruction(InstructionType::PushStr) {
writeln!(writer, " ;; -- {:?} {}", token.typ, strings[token.value].escape_debug())?;
} else {
writeln!(writer, " ;; -- {:?}", token.typ)?;
}
} else {
if ti != 0{
if &tokens[ti-1].typ == &OpType::Keyword(KeywordType::Else) ||
&tokens[ti-1].typ == &OpType::Keyword(KeywordType::End){
writeln!(writer, "addr_{ti}:")?;
}
}
if ti + 1 < tokens.len() && &tokens[ti+1].typ == &OpType::Keyword(KeywordType::End) {
writeln!(writer, "addr_{ti}:")?;
}
match &token.typ {
OpType::Keyword(keyword) => {
match keyword {
&KeywordType::End |
&KeywordType::While => {
writeln!(writer, "addr_{ti}:")?;
}
_ => ()
}
}
_ => ()
}
}
match token.typ.clone() {
// stack
OpType::Instruction(instruction) => {
match instruction {
InstructionType::PushInt => {
writeln!(writer, " ;; -- push int {}", token.value)?;
writeln!(writer, " mov rax, {}", token.value)?;
writeln!(writer, " push rax")?;
ti += 1;
},
InstructionType::PushStr => {
writeln!(writer, " ;; -- push str \"{}\"", token.text.escape_default())?;
writeln!(writer, " mov rax, {}", token.text.len())?;
writeln!(writer, " push rax")?;
writeln!(writer, " push str_{}", strings.len())?;
writeln!(writer, " mov rax, str_{}", strings.len())?;
writeln!(writer, " push rax")?;
strings.push(token.text.clone());
ti += 1;
}
InstructionType::Drop => {
writeln!(writer, " ;; -- drop")?;
writeln!(writer, " pop rax")?;
ti += 1;
},
InstructionType::Print => {
writeln!(writer, " ;; -- print")?;
writeln!(writer, " pop rdi")?;
writeln!(writer, " call print")?;
ti += 1;
},
InstructionType::Dup => {
writeln!(writer, " ;; -- dup")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " push rax")?;
writeln!(writer, " push rax")?;
@@ -119,7 +155,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
},
InstructionType::Rot => {
writeln!(writer, " ;; -- rot")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " pop rcx")?;
@@ -130,7 +165,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Swap => {
writeln!(writer, " ;; -- swap")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " push rax")?;
@@ -139,7 +173,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Over => {
writeln!(writer, " ;; -- over")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " push rbx")?;
@@ -148,15 +181,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
//mem
InstructionType::Mem => {
writeln!(writer, " ;; -- mem")?;
writeln!(writer, " push mem")?;
ti += 1;
}
InstructionType::Load8 => {
writeln!(writer, " ;; -- load")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " xor rbx, rbx")?;
writeln!(writer, " mov bl, byte [rax]")?;
@@ -165,14 +190,12 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
}
InstructionType::Store8 => {
writeln!(writer, " ;; -- store")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " mov byte [rax], bl")?;
ti += 1;
}
InstructionType::Load32 => {
writeln!(writer, " ;; -- load")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " xor rbx, rbx")?;
writeln!(writer, " mov bl, dword [rax]")?;
@@ -181,14 +204,12 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
}
InstructionType::Store32 => {
writeln!(writer, " ;; -- store")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " mov dword[rax], bl")?;
ti += 1;
}
InstructionType::Load64 => {
writeln!(writer, " ;; -- load")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " xor rbx, rbx")?;
writeln!(writer, " mov bl, qword [rax]")?;
@@ -197,7 +218,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
}
InstructionType::Store64 => {
writeln!(writer, " ;; -- store")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " mov qword [rax], bl")?;
@@ -206,7 +226,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
// math
InstructionType::Plus => {
writeln!(writer, " ;; -- plus")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " add rax, rbx")?;
@@ -214,7 +233,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Minus => {
writeln!(writer, " ;; -- minus")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " sub rbx, rax")?;
@@ -222,7 +240,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Equals => {
writeln!(writer, " ;; -- equals")?;
writeln!(writer, " mov rcx, 0")?;
writeln!(writer, " mov rdx, 1")?;
writeln!(writer, " pop rax")?;
@@ -233,7 +250,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Lt => {
writeln!(writer, " ;; -- lt")?;
writeln!(writer, " mov rcx, 0")?;
writeln!(writer, " mov rdx, 1")?;
writeln!(writer, " pop rbx")?;
@@ -244,7 +260,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Gt => {
writeln!(writer, " ;; -- gt")?;
writeln!(writer, " mov rcx, 0")?;
writeln!(writer, " mov rdx, 1")?;
writeln!(writer, " pop rbx")?;
@@ -255,7 +270,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::NotEquals => {
writeln!(writer, " ;; -- not equals")?;
writeln!(writer, " mov rcx, 1")?;
writeln!(writer, " mov rdx, 0")?;
writeln!(writer, " pop rax")?;
@@ -266,7 +280,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Le => {
writeln!(writer, " ;; -- lt")?;
writeln!(writer, " mov rcx, 0")?;
writeln!(writer, " mov rdx, 1")?;
writeln!(writer, " pop rbx")?;
@@ -277,7 +290,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Ge => {
writeln!(writer, " ;; -- gt")?;
writeln!(writer, " mov rcx, 0")?;
writeln!(writer, " mov rdx, 1")?;
writeln!(writer, " pop rbx")?;
@@ -288,7 +300,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Band => {
writeln!(writer, " ;; -- band")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " and rbx, rax")?;
@@ -296,7 +307,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Bor => {
writeln!(writer, " ;; -- bor")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " or rbx, rax")?;
@@ -304,7 +314,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Shr => {
writeln!(writer, " ;; -- shr")?;
writeln!(writer, " pop rcx")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " shr rbx, cl")?;
@@ -312,7 +321,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Shl => {
writeln!(writer, " ;; -- shl")?;
writeln!(writer, " pop rcx")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " shl rbx, cl")?;
@@ -320,7 +328,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::DivMod => {
writeln!(writer, " ;; -- div")?;
writeln!(writer, " xor rdx, rdx")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " pop rax")?;
@@ -330,7 +337,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Mul => {
writeln!(writer, " ;; -- mul")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " mul rbx")?;
@@ -338,14 +344,12 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Syscall0 => {
writeln!(writer, " ;; -- syscall0")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " syscall")?;
writeln!(writer, " push rax")?;
ti += 1;
},
InstructionType::Syscall1 => {
writeln!(writer, " ;; -- syscall1")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?;
writeln!(writer, " syscall")?;
@@ -353,7 +357,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Syscall2 => {
writeln!(writer, " ;; -- syscall2")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?;
writeln!(writer, " pop rsi")?;
@@ -362,7 +365,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Syscall3 => {
writeln!(writer, " ;; -- syscall3")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?;
writeln!(writer, " pop rsi")?;
@@ -373,7 +375,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Syscall4 => {
writeln!(writer, " ;; -- syscall4")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?;
writeln!(writer, " pop rsi")?;
@@ -384,7 +385,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Syscall5 => {
writeln!(writer, " ;; -- syscall5")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?;
writeln!(writer, " pop rsi")?;
@@ -396,7 +396,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
},
InstructionType::Syscall6 => {
writeln!(writer, " ;; -- syscall6")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " pop rdi")?;
writeln!(writer, " pop rsi")?;
@@ -409,24 +408,65 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
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,
InstructionType::CastInt => ti += 1,
InstructionType::None => {
println!("{:?}", token);
unreachable!()
},
InstructionType::FnCall => {
writeln!(writer, " ;; -- FnCall")?;
writeln!(writer, " call func_{}", token.text)?;
ti += 1;
},
InstructionType::Return => {
writeln!(writer, " ;; -- Return")?;
writeln!(writer, " sub rbp, 8")?;
writeln!(writer, " mov rbx, qword [rbp]")?;
writeln!(writer, " push rbx")?;
writeln!(writer, " ret")?;
ti += 1;
},
InstructionType::CastBool => {
ti += 1;
}
InstructionType::CastPtr => {
ti += 1;
}
InstructionType::CastInt => {
ti += 1;
}
InstructionType::CastVoid => {
ti += 1;
}
InstructionType::TypeBool => {
ti += 1;
}
InstructionType::TypePtr => {
ti += 1;
}
InstructionType::TypeInt => {
ti += 1;
}
InstructionType::TypeVoid => {
ti += 1;
}
InstructionType::TypeStr => {
ti += 1;
}
InstructionType::TypeAny => {
ti += 1;
}
InstructionType::Returns => {
ti += 1;
}
InstructionType::With => {
ti += 1;
}
InstructionType::ConstUse => {
writeln!(writer, " mov rax, qword [const_{}]", token.text)?;
writeln!(writer, " push rax")?;
ti += 1;
},
}
}
@@ -436,32 +476,27 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
// block
KeywordType::If => {
writeln!(writer, " ;; -- if")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " test rax, rax")?;
writeln!(writer, " jz addr_{}", token.jmp)?;
ti += 1;
},
KeywordType::Else => {
writeln!(writer, " ;; -- else")?;
writeln!(writer, " jmp addr_{}", token.jmp)?;
ti += 1;
},
KeywordType::While => {
writeln!(writer, " ;; -- while")?;
ti += 1;
}
KeywordType::Do => {
writeln!(writer, " ;; -- do")?;
writeln!(writer, " pop rax")?;
writeln!(writer, " test rax, rax")?;
writeln!(writer, " jz addr_{}", token.jmp)?;
ti += 1;
}
KeywordType::End => {
writeln!(writer, " ;; -- end")?;
if ti + 1 != token.jmp {
writeln!(writer, " jmp addr_{}", token.jmp)?;
// writeln!(writer, " jmp addr_{}", token.jmp)?;
}
ti += 1;
},
@@ -470,11 +505,19 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
ti += 1;
}
KeywordType::Include => unreachable!(),
KeywordType::Constant => todo!(),
KeywordType::Function => {
writeln!(writer, "func_{}:", token.text)?;
KeywordType::Constant => {
// TODO: after we add c style strings add supoort for them in constants
constants.push((token.text.clone(), Some(token.value), None));
ti += 1;
},
KeywordType::Function => {
writeln!(writer, "func_{}:", token.text)?;
writeln!(writer, " pop rbx")?;
writeln!(writer, " mov qword [rbp], rbx")?;
writeln!(writer, " add rbp, 8")?;
ti += 1;
},
KeywordType::FunctionDo => ti += 1,
}
}
}
@@ -491,11 +534,27 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
writeln!(writer, " str_{}: db {} ; {}", i, s_list, s.escape_default())?;
}
for (_, s) in constants.iter().enumerate() {
if let Some(v) = &s.1 {
writeln!(writer, " const_{}: dq {}", s.0, v)?;
} else if let Some(_v) = &s.2 {
todo!();
} else {
unreachable!();
}
}
writeln!(writer, "segment .bss")?;
for (_, s) in memories.iter().enumerate() {
writeln!(writer, " mem_{}: resb {}", s.0, s.1)?;
}
writeln!(writer, " mem: resb {}", crate::compile::MEM_SZ)?;
writeln!(writer, " ret_stack: resq 256")?;
// for t in tokens {
// println!("{t:?}");
// }
writer.flush()?;
linux_x86_64_compile_and_link(&of_a, &of_o, &of_c, args.quiet)?;
@@ -504,5 +563,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
return Ok(c);
}
Ok(0)
}

View File

@@ -1,5 +1,4 @@
pub const ALLOW_MACRO_REDEFINITION: bool = true;
#[derive(Debug, Clone, PartialEq)]
@@ -33,7 +32,6 @@ pub enum InstructionType {
// mem
Mem,
Load8,
Store8,
Load32,
@@ -53,10 +51,23 @@ pub enum InstructionType {
CastBool,
CastPtr,
CastInt,
CastVoid,
// typing
TypeBool,
TypePtr,
TypeInt,
TypeVoid,
TypeStr,
TypeAny,
Returns,
With,
FnCall,
Return,
MemUse,
ConstUse,
Return,
None // Used for macros and any other non built in word definitions
}
@@ -70,7 +81,8 @@ pub enum KeywordType {
Include,
Memory,
Constant,
Function
Function,
FunctionDo
}
#[derive(Debug, Clone, PartialEq)]
@@ -137,7 +149,6 @@ impl OpType {
InstructionType::Shl => "shl",
InstructionType::DivMod => "divmod",
InstructionType::Mul => "*",
InstructionType::Mem => "mem",
InstructionType::Load8 => "load8",
InstructionType::Store8 => "store8",
InstructionType::Load32 => "load32",
@@ -154,10 +165,20 @@ impl OpType {
InstructionType::CastBool => "cast(bool",
InstructionType::CastPtr => "cast(ptr)",
InstructionType::CastInt => "cast(int)",
InstructionType::MemUse => "MemUse",
InstructionType::CastVoid => "cast(void)",
InstructionType::None => "None",
InstructionType::FnCall => "Function Call",
InstructionType::MemUse => "Memory use (internal)",
InstructionType::FnCall => "Function Call (Internal)",
InstructionType::ConstUse => "Constant Use (Internal)",
InstructionType::Return => "return",
InstructionType::TypeBool => "bool",
InstructionType::TypePtr => "ptr",
InstructionType::TypeInt => "int",
InstructionType::TypeVoid => "void",
InstructionType::TypeStr => "str",
InstructionType::Returns => "returns",
InstructionType::With => "with",
InstructionType::TypeAny => "any",
}
}
OpType::Keyword(keyword) => {
@@ -171,6 +192,7 @@ impl OpType {
KeywordType::Memory => "memory",
KeywordType::Function => "fn",
KeywordType::Constant => "const",
KeywordType::FunctionDo => "do",
}
}
@@ -226,6 +248,8 @@ pub enum Types {
Bool,
Ptr,
Int,
Void,
Str,
Any
// U8,
// U16,

View File

@@ -96,12 +96,6 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
// let _ = io::stdout().flush();
ti += 1;
},
// mem
InstructionType::Mem => {
stack.push(0);
ti += 1;
}
InstructionType::Load8 |
InstructionType::Load32 |
InstructionType::Load64 => {
@@ -294,12 +288,22 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
stack.push(*m);
ti += 1;
},
InstructionType::CastBool => ti += 1,
InstructionType::CastPtr => ti += 1,
InstructionType::CastInt => ti += 1,
InstructionType::CastBool |
InstructionType::CastPtr |
InstructionType::CastInt |
InstructionType::FnCall |
InstructionType::Return |
InstructionType::CastVoid |
InstructionType::TypeBool |
InstructionType::TypePtr |
InstructionType::TypeInt |
InstructionType::TypeVoid |
InstructionType::TypeStr |
InstructionType::TypeAny |
InstructionType::Returns |
InstructionType::With => ti += 1,
InstructionType::None => unreachable!(),
InstructionType::FnCall => todo!(),
InstructionType::Return => todo!(),
InstructionType::ConstUse => todo!(),
}
}
@@ -336,6 +340,7 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
KeywordType::Include => unreachable!(),
KeywordType::Constant => todo!(),
KeywordType::Function => todo!(),
KeywordType::FunctionDo => todo!(),
}
}

View File

@@ -1,5 +1,5 @@
use crate::{constants::{Token, TokenType}, preprocessor::preprocess, Args};
use crate::{constants::{Token, TokenType}, Args};
use color_eyre::Result;
fn lex_word(s: String, tok_type: TokenType) -> (TokenType, String) {
@@ -89,7 +89,7 @@ fn lex_line(text: &str) -> Vec<(usize, String, TokenType)> {
tokens
}
pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, args: &Args) -> Result<Vec<Token>> {
pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, _args: &Args) -> Result<Vec<Token>> {
let lines: Vec<(usize, &str)> = code
.split(['\n', '\r'])
.enumerate()

View File

@@ -53,8 +53,12 @@ pub struct Args {
/// Unsafe mode, disables typechecking
#[arg(long="unsafe", default_value_t = false)]
unsaf: bool
unsaf: bool,
/// Optimisation level, available levels: 'D': debug, '0': No optimisations
#[arg(long, short='O', default_value_t=String::from("0"))]
optimisation: String,
//#[arg(long, short='F')]
//features: Vec<String>,
@@ -82,7 +86,7 @@ fn main() {
return;
};
let Ok(tokens) = typechecker::typecheck(&tokens, &args) else {
let Ok(tokens) = typechecker::typecheck(tokens, &args) else {
error!("Typechecking failed, exiting!");
return;
};

View File

@@ -1,11 +1,12 @@
use std::ops::Deref;
use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType}, lerror, preprocessor::preprocess, Args};
use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType}, lerror, preprocessor::Preprocessor, Args};
use color_eyre::Result;
use eyre::eyre;
pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
let mut stack: Vec<usize> = Vec::new();
for ip in 0..program.len() {
let op = &program.clone()[ip];
match op.typ {
@@ -15,9 +16,12 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
stack.push(ip);
}
OpType::Keyword(KeywordType::Else) => {
let if_ip = stack.pop().unwrap();
let if_ip = if let Some(x) = stack.pop() { x } else {
lerror!(&op.loc, "Unclosed-if else block");
return Err(eyre!("Cross referencing"));
};
if program[if_ip].typ != OpType::Keyword(KeywordType::If) {
lerror!(&op.clone().loc,"'end' can only close 'if' blocks");
lerror!(&op.clone().loc,"'else' can only close 'if' blocks");
return Err(eyre!("Bad block"));
}
@@ -25,36 +29,48 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
stack.push(ip);
},
OpType::Keyword(KeywordType::End) => {
let block_ip = stack.pop().unwrap();
let block_ip = if let Some(block_ip) = stack.pop() { block_ip } else {
lerror!(&op.loc, "Unclosed if, if-else, while-do, function, memory, or constant");
return Err(eyre!("Cross referencing"));
};
match &program[block_ip].typ {
OpType::Keyword(KeywordType::If) |
OpType::Keyword(KeywordType::Else) => {
program[block_ip].jmp = ip;
program[ip].jmp = ip + 1;
}
if program[block_ip].typ == OpType::Keyword(KeywordType::If) ||
program[block_ip].typ == OpType::Keyword(KeywordType::Else) {
program[block_ip].jmp = ip;
program[ip].jmp = ip + 1;
OpType::Keyword(KeywordType::Do) => {
program[ip].jmp = program[block_ip].jmp;
program[block_ip].jmp = ip + 1;
}
OpType::Keyword(KeywordType::FunctionDo) => {
program[ip].typ = OpType::Instruction(InstructionType::Return);
}
OpType::Keyword(KeywordType::Memory) |
OpType::Keyword(KeywordType::Function) |
OpType::Keyword(KeywordType::Constant) => (),
} else if program[block_ip].typ == OpType::Keyword(KeywordType::Do) {
program[ip].jmp = program[block_ip].jmp;
program[block_ip].jmp = ip + 1;
} else if program[block_ip].typ == OpType::Keyword(KeywordType::Function) {
program[ip].typ = OpType::Instruction(InstructionType::Return);
program[block_ip].typ = OpType::Keyword(KeywordType::Do);
} else {
lerror!(&op.clone().loc,"'end' can only close 'if' blocks");
return Err(eyre!(""));
a => {
println!("{a:?}");
lerror!(&op.clone().loc,"'end' can only close if, if-else, while-do, function, memory, or constant blocks");
return Err(eyre!(""));
}
}
}
OpType::Keyword(KeywordType::Do) => {
let block_ip = stack.pop().unwrap();
let block_ip = if let Some(x) = stack.pop() { x } else {
lerror!(&op.loc, "Unclosed while-do block");
return Err(eyre!("Cross referencing"));
};
if program[block_ip].typ == OpType::Keyword(KeywordType::Function) {
program[ip].typ = OpType::Keyword(KeywordType::Function);
program[ip].typ = OpType::Keyword(KeywordType::FunctionDo);
}
program[ip].jmp = block_ip;
// println!("{}", block_ip);
stack.push(ip);
}
_ => ()
@@ -63,7 +79,7 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
}
if !stack.is_empty() {
println!("{:?}", stack);
lerror!(&program[stack.pop().expect("Empy stack")].clone().loc,"Unclosed block");
lerror!(&program[stack.pop().expect("Empy stack")].clone().loc,"Unclosed block, {:?}", program[stack.pop().expect("Empy stack")].clone());
return Err(eyre!("Unclosed block"));
}
@@ -116,14 +132,13 @@ impl Parser {
}
};
//"print" => tokens.push(Operator::new(OpType::Print, 0, token.file.clone(), token.line, token.col)),
}
tokens = cross_ref(tokens.clone())?;
let t = preprocess(tokens, args)?;
Ok(t.0)
let t = Preprocessor::new(tokens.clone(), args).preprocess()?.get_ops();
let t = cross_ref(t.clone())?;
Ok(t)
}
}
@@ -161,7 +176,6 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
// mem
"mem" => OpType::Instruction(InstructionType::Mem),
"load8" => OpType::Instruction(InstructionType::Load8),
"store8" => OpType::Instruction(InstructionType::Store8),
"load32" => OpType::Instruction(InstructionType::Load32),
@@ -176,9 +190,10 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
"syscall4" => OpType::Instruction(InstructionType::Syscall4),
"syscall5" => OpType::Instruction(InstructionType::Syscall5),
"syscall6" => OpType::Instruction(InstructionType::Syscall6),
"cast(bool" => OpType::Instruction(InstructionType::CastBool),
"cast(bool)" => OpType::Instruction(InstructionType::CastBool),
"cast(ptr)" => OpType::Instruction(InstructionType::CastPtr),
"cast(int)" => OpType::Instruction(InstructionType::CastInt),
"cast(void)" => OpType::Instruction(InstructionType::CastVoid),
// block
"if" => OpType::Keyword(KeywordType::If),
"else" => OpType::Keyword(KeywordType::Else),
@@ -189,6 +204,15 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
"memory" => OpType::Keyword(KeywordType::Memory),
"const" => OpType::Keyword(KeywordType::Constant),
"fn" => OpType::Keyword(KeywordType::Function),
"return" => OpType::Instruction(InstructionType::Return),
"returns" => OpType::Instruction(InstructionType::Returns),
"bool" => OpType::Instruction(InstructionType::TypeBool),
"int" => OpType::Instruction(InstructionType::TypeInt),
"ptr" => OpType::Instruction(InstructionType::TypePtr),
"void" => OpType::Instruction(InstructionType::TypeVoid),
"any" => OpType::Instruction(InstructionType::TypeAny),
"str" => OpType::Instruction(InstructionType::TypeStr),
"with" => OpType::Instruction(InstructionType::With),
_ => OpType::Instruction(InstructionType::None)
}

View File

@@ -2,7 +2,7 @@
use color_eyre::Result;
use eyre::eyre;
use crate::{constants::{Token, OpType, InstructionType, Loc, Operator}, parser::lookup_word, lerror};
use crate::{constants::{ OpType, InstructionType, Loc, Operator}, lerror};
fn stack_pop(stack: &mut Vec<usize>, loc: &Loc) -> Result<usize> {
if let Some(i) = stack.pop() { Ok(i) } else {
@@ -14,19 +14,13 @@ fn stack_pop(stack: &mut Vec<usize>, loc: &Loc) -> Result<usize> {
pub fn precompile(tokens: &Vec<Operator>) -> Result<Vec<usize>>{
let mut stack: Vec<usize> = Vec::new();
for token in tokens.iter() {
match token.typ.clone() {
OpType::Instruction(i) => {
let loc = token.loc.clone();
match i {
InstructionType::PushInt => {
if let Ok(i) = token.text.parse::<usize>() {
stack.push(i);
} else {
lerror!(&token.loc, "Bad number");
return Err(eyre!(""));
}
stack.push(token.value);
},
InstructionType::Plus => {
let a = stack_pop(&mut stack, &loc)?;

View File

@@ -1,251 +1,364 @@
use std::collections::HashMap;
use std::ops::Deref;
use std::path::{PathBuf, Path};
use color_eyre::Result;
use eyre::eyre;
use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType, Operator};
use crate::constants::{Loc, OpType, TokenType, KeywordType, InstructionType, Operator};
use crate::lexer::lex;
use crate::precompiler::precompile;
use crate::{lerror, lnote, Args, warn, linfo, parser};
use crate::{lerror, Args, warn, linfo, parser};
use crate::parser::lookup_word;
#[derive(Debug)]
pub struct Function {
pub loc: Loc,
pub name: String
}
type Functions = HashMap<String, Function>;
type Memories = HashMap<String, usize>;
pub fn preprocess(tokens: Vec<Operator>, args: &Args) -> Result<(Vec<Operator>, Functions)>{
let mut program: Vec<Operator> = Vec::new();
let mut functions: Functions = HashMap::new();
let mut memories: Memories = HashMap::new();
let mut rtokens = tokens;
rtokens.reverse();
while !rtokens.is_empty() {
let mut token = rtokens.pop().unwrap();
let op_type = token.typ.clone();
match token.clone() {
_ if op_type == OpType::Keyword(KeywordType::Include) => {
if rtokens.is_empty() {
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.tok_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();
in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| (*f).to_string()).collect::<Vec<String>>());
let mut include_code = String::new();
if include_path.text.chars().collect::<Vec<char>>()[0] == '.' {
let p = Path::new(include_path.loc.0.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)?;
}
}
}
if include_code.is_empty() {
lerror!(&include_path.loc, "Include file in path '{}' was not found or is empty", include_path.text);
return Err(eyre!(""));
}
let code = lex(&include_code, &args.in_file, &args)?;
let mut p = parser::Parser::new(code);
let mut code = p.parse(args)?;
code.reverse();
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.tok_typ != TokenType::Word {
lerror!(&memory_name.loc, "Bad memory name, expected {} but found {}", TokenType::Word.human(), memory_name.typ.human());
return Err(eyre!(""));
}
if functions.get(&memory_name.text).is_some() {
lerror!(&memory_name.loc, "Memory name cannot replace function name, got {}", memory_name.text);
let m = functions.get(&memory_name.text).unwrap();
linfo!(&m.loc, "Function found here");
return Err(eyre!(""));
}
let mut code: Vec<Operator> = Vec::new();
let mut depth = 0;
while !rtokens.is_empty() {
let t = rtokens.pop().unwrap();
let typ = t.typ.clone();
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 = res[0];
token.addr = Some(memories.len());
program.push(token);
memories.insert(memory_name.text, memories.len());
}
_ if op_type == OpType::Keyword(KeywordType::Function) => {
if rtokens.is_empty() {
lerror!(&token.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human());
return Err(eyre!(""));
}
let function_name = rtokens.pop().unwrap();
if function_name.tok_typ != TokenType::Word {
lerror!(&function_name.loc, "Bad Function name, expected {} but found {}", TokenType::Word.human(), function_name.typ.human());
return Err(eyre!(""));
}
if memories.get(&function_name.text).is_some() {
lerror!(&function_name.loc, "Function name cannot replace memory name, got {}", function_name.text);
return Err(eyre!(""));
}
if functions.get(&function_name.text).is_some() {
lerror!(&function_name.loc, "Functions cannot be redefined, got {}", function_name.text);
return Err(eyre!(""));
}
functions.insert(function_name.text.clone(), Function{
loc: function_name.loc.clone(),
name: function_name.text.clone(),
});
token.text = function_name.text;
rtokens.pop();
program.push(token);
}
_ => {
if op_type == OpType::Keyword(KeywordType::Do) {
println!("{:?}", token);
}
program.push(token);
}
}
}
//* Feel free to fix this horrifying shit
//* i wanna kms
let mut times = 0;
while program.iter().map(|f| {
if f.tok_typ == TokenType::Word && f.typ != OpType::Instruction(InstructionType::FnCall) && f.typ != OpType::Instruction(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
}
}).collect::<Vec<OpType>>().contains(&OpType::Instruction(InstructionType::None)){
if times >= 50 {
warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it");
break
}
program = expand(program, &functions, &memories)?;
times += 1;
}
Ok((program, functions))
#[derive(Debug)]
pub struct Constant {
pub loc: Loc,
pub name: String
}
pub fn expand(tokens: Vec<Operator>, funcs: &Functions, mems: &Memories) -> Result<Vec<Operator>> {
let mut program: Vec<Operator> = Vec::new();
#[derive(Debug)]
pub struct Memory {
pub loc: Loc,
pub id: usize
}
let mut rtokens = tokens.clone();
rtokens.reverse();
type Functions = HashMap<String, Function>;
type Memories = HashMap<String, Memory>;
type Constants = HashMap<String, Constant>;
while !rtokens.is_empty() {
let op = rtokens.pop().unwrap();
let op_type = op.typ.clone();
if op.tok_typ.clone() == TokenType::Word {
match op_type {
OpType::Instruction(InstructionType::None) => {
let m = funcs.get(&op.text);
let mem = mems.get(&op.text);
if let Some(m) = m {
let mut t = op.clone();
t.typ = OpType::Instruction(InstructionType::FnCall);
t.text = m.name.clone();
program.push(t);
} else
if let Some(mem) = mem {
let mut t = op.clone();
t.addr = Some(*mem);
t.typ = OpType::Instruction(InstructionType::MemUse);
program.push(t);
}
else {
lerror!(&op.loc, "expand: Unknown word '{}'", op.text.clone());
return Err(eyre!(""));
}
}
_ => {
program.push(op.clone());
}
}
} else {
program.push(op.clone());
pub struct Preprocessor<'a> {
program: Vec<Operator>,
functions: Functions,
memories: Memories,
constants: Constants,
args: &'a Args
}
impl<'a> Preprocessor<'a> {
pub fn new(prog: Vec<Operator>, args: &'a Args) -> Self {
Self {
program: prog,
args: args,
functions: HashMap::new(),
memories: HashMap::new(),
constants: HashMap::new(),
}
if op.typ == OpType::Keyword(KeywordType::Do) {
println!("expand: {:?}", op);
}
}
pub fn preprocess(&mut self) -> Result<&mut Preprocessor<'a>>{
// println!("pre: has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
let mut program: Vec<Operator> = Vec::new();
let mut rtokens = self.program.clone();
rtokens.reverse();
while !rtokens.is_empty() {
let mut token = rtokens.pop().unwrap();
// println!("{token:?}");
let op_type = token.typ.clone();
match token.clone() {
_ if op_type == OpType::Keyword(KeywordType::Include) => {
if rtokens.is_empty() {
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.tok_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 = self.args.include.clone();
in_paths.append(&mut crate::DEFAULT_INCLUDES.to_vec().clone().iter().map(|f| (*f).to_string()).collect::<Vec<String>>());
let mut include_code = String::new();
if include_path.text.chars().collect::<Vec<char>>()[0] == '.' {
let p = Path::new(include_path.loc.0.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)?;
}
}
}
if include_code.is_empty() {
lerror!(&include_path.loc, "Include file in path '{}' was not found or is empty", include_path.text);
return Err(eyre!(""));
}
let code = lex(&include_code, &self.args.in_file, &self.args)?;
let mut p = parser::Parser::new(code);
let mut code = p.parse(self.args)?;
code.reverse();
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!(""));
}
Ok(program)
let memory_name = rtokens.pop().unwrap();
self.is_word_available(&memory_name, KeywordType::Function)?;
let mut code: Vec<Operator> = Vec::new();
let mut depth = 0;
while !rtokens.is_empty() {
let t = rtokens.pop().unwrap();
let typ = t.typ.clone();
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 = res[0];
token.addr = Some(self.memories.len());
program.push(token.clone());
self.memories.insert(memory_name.text, Memory { loc: token.loc, id: self.memories.len() });
}
_ if op_type == OpType::Keyword(KeywordType::Function) => {
if rtokens.is_empty() {
lerror!(&token.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human());
return Err(eyre!(""));
}
let function_name = rtokens.pop().unwrap();
self.is_word_available(&function_name, KeywordType::Function)?;
self.functions.insert(function_name.text.clone(), Function{
loc: function_name.loc.clone(),
name: function_name.text.clone(),
});
token.text = function_name.text;
// println!("{:?}", token);
program.push(token);
}
_ if op_type == OpType::Keyword(KeywordType::Constant) => {
if rtokens.is_empty() {
lerror!(&token.loc, "Constant name not found, expected {} but found nothing", TokenType::Word.human());
return Err(eyre!(""));
}
let const_name = rtokens.pop().unwrap();
self.is_word_available(&const_name, KeywordType::Function)?;
self.constants.insert(const_name.text.clone(), Constant{
loc: const_name.loc.clone(),
name: const_name.text.clone(),
});
token.text = const_name.text;
let item = rtokens.pop().unwrap();
if item.tok_typ == TokenType::Int {
token.value = item.value;
}
if let None = rtokens.pop() {
lerror!(&token.loc, "Constant was not closed with an 'end' instruction, expected 'end' but found nothing");
return Err(eyre!(""));
}
// token.value =
program.push(token);
}
_ => {
program.push(token);
}
}
}
self.program = program;
// println!("has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
//* Feel free to fix this horrifying shit
//* i wanna kms
let mut times = 0;
// dbg!(program.clone());
while self.program.iter().map(|f| {
if f.tok_typ == TokenType::Word && f.typ != OpType::Instruction(InstructionType::FnCall) && f.typ != OpType::Instruction(InstructionType::MemUse) && f.typ != OpType::Keyword(KeywordType::Function) && f.typ != OpType::Keyword(KeywordType::Constant) && f.typ != OpType::Instruction(InstructionType::ConstUse) {
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
}
}).collect::<Vec<OpType>>().contains(&OpType::Instruction(InstructionType::None)){
if times >= 50 {
warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it");
break
}
self.expand()?;
times += 1;
}
Ok(self)
}
pub fn expand(&mut self) -> Result<()> {
let mut program: Vec<Operator> = Vec::new();
// println!("{:?}", self.functions);
let mut rtokens = self.program.clone();
rtokens.reverse();
while !rtokens.is_empty() {
let op = rtokens.pop().unwrap();
let op_type = op.typ.clone();
if op.tok_typ.clone() == TokenType::Word {
match op_type {
OpType::Instruction(InstructionType::None) => {
let m = self.functions.get(&op.text);
let mem = self.memories.get(&op.text);
let cons = self.constants.get(&op.text);
if let Some(m) = m {
// println!("------ FOUND FUNCTION {} -----------", m.name);
let mut t = op.clone();
t.typ = OpType::Instruction(InstructionType::FnCall);
t.text = m.name.clone();
program.push(t.clone());
// println!("##### {:?}", t);
} else if let Some(mem) = mem {
let mut t = op.clone();
t.addr = Some(mem.deref().id);
t.typ = OpType::Instruction(InstructionType::MemUse);
program.push(t);
} else if let Some(cons) = cons {
let mut t = op.clone();
t.text = cons.deref().name.clone();
t.typ = OpType::Instruction(InstructionType::ConstUse);
program.push(t);
} else {
lerror!(&op.loc, "Preprocess: Unknown word '{}'", op.text.clone());
return Err(eyre!(""));
}
}
_ => {
program.push(op.clone());
}
}
} else {
program.push(op.clone());
}
// if op.typ == OpType::Keyword(KeywordType::Do) {
// println!("expand: {:?}", op);
// program.push(op.clone());
// }
}
// println!("expand: has do tokens: {:?}", program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
self.program = program;
// println!("{:#?}", self.program);
println!("{:?}", self.program.last().unwrap());
Ok(())
}
pub fn get_ops(&mut self) -> Vec<Operator> {
self.program.clone()
}
pub fn is_word_available(&self, word: &Operator, typ: KeywordType) -> Result<bool> {
match typ {
KeywordType::Memory |
KeywordType::Constant |
KeywordType::Function => (),
_ => panic!()
}
if word.tok_typ != TokenType::Word {
lerror!(&word.loc, "Bad Function name, expected {} but found {}", TokenType::Word.human(), word.typ.human());
return Err(eyre!(""));
}
let m = self.memories.get(&word.text);
if let Some(m) = m {
if typ != KeywordType::Memory {
lerror!(&word.loc, "{typ:?} cannot replace memory, got {}", word.text);
linfo!(&m.loc, "first definition here");
return Err(eyre!(""));
} else {
lerror!(&word.loc, "Memories cannot be redefined, got {}", word.text);
linfo!(&m.loc, "first definition here");
return Err(eyre!(""));
}
}
let f = self.functions.get(&word.text);
if let Some(f) = f {
if typ != KeywordType::Function {
lerror!(&word.loc, "{typ:?} cannot replace function, got {}", word.text);
linfo!(&f.loc, "first definition here");
return Err(eyre!(""));
} else {
lerror!(&word.loc, "Functions cannot be redefined, got {}", word.text);
linfo!(&f.loc, "first definition here");
return Err(eyre!(""));
}
}
let c = self.constants.get(&word.text);
if let Some(c) = c {
if typ != KeywordType::Constant {
lerror!(&word.loc, "{typ:?} cannot replace constant, got {}", word.text);
linfo!(&c.loc, "first definition here");
return Err(eyre!(""));
} else {
lerror!(&word.loc, "Constants cannot be redefined, got {}", word.text);
linfo!(&c.loc, "first definition here");
return Err(eyre!(""));
}
}
Ok(true)
}
}

View File

@@ -1,19 +1,43 @@
use crate::{constants::{Operator, Types, OpType, KeywordType, InstructionType}, Args, lerror, warn};
use std::collections::HashMap;
use crate::{constants::{Operator, Types, OpType, KeywordType, InstructionType}, Args, lerror, warn, note};
use color_eyre::Result;
use eyre::eyre;
#[derive(Debug, Clone)]
struct Function {
args: Vec<Types>,
returns: Vec<Types>,
}
impl Function {
pub fn default() -> Self {
Self {
args: Vec::new(),
returns: Vec::new(),
}
}
}
pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
pub fn typecheck(ops: Vec<Operator>, args: &Args) -> Result<Vec<Operator>>{
if args.unsaf {
if !args.quiet {
warn!("Unsafe mode enabled, disabling typechecker, goodluck");
}
return Ok(ops.to_vec());
}
let mut functions: HashMap<String, Function> = HashMap::new();
// let mut in_function: (String, Function) = (String::new(), Function::default());
let mut stack: Vec<Types> = Vec::new();
for op in ops {
let mut stack_snapshots: Vec<Vec<Types>> = Vec::new();
let mut rtokens = ops.clone();
rtokens.reverse();
// println!("{:#?}", ops);
while !rtokens.is_empty() {
let op = rtokens.pop().unwrap();
println!("{:?}", stack.clone());
// println!("{:?}", op);
// println!("{}", ops.len());
match op.typ.clone() {
OpType::Keyword(keyword) => {
match keyword {
@@ -24,13 +48,94 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
stack_pop(&mut stack, &op, &[Types::Bool])?;
},
KeywordType::Function => {
let name = op.text.clone();
if let Some(p) = rtokens.pop() {
if p.typ != OpType::Instruction(InstructionType::With){
lerror!(&op.loc, "Expected {:?}, got {:?}", OpType::Instruction(InstructionType::With), p.typ);
return Err(eyre!(""));
}
} else {
lerror!(&op.loc, "Expected {:?}, got nothing", OpType::Instruction(InstructionType::With));
return Err(eyre!(""));
}
let mut p = rtokens.pop();
let mut func = Function {
args: Vec::new(),
returns: Vec::new(),
};
let mut return_args = false;
while p.as_ref().is_some() {
let op = p.as_ref().unwrap();
if op.typ == OpType::Instruction(InstructionType::TypeBool) ||
op.typ == OpType::Instruction(InstructionType::TypeInt) ||
op.typ == OpType::Instruction(InstructionType::TypePtr) ||
op.typ == OpType::Instruction(InstructionType::TypeVoid) {
let t = if op.typ == OpType::Instruction(InstructionType::TypeInt) {
Types::Int
} else
if op.typ == OpType::Instruction(InstructionType::TypeBool) {
Types::Bool
} else
if op.typ == OpType::Instruction(InstructionType::TypePtr) {
Types::Ptr
} else
if op.typ == OpType::Instruction(InstructionType::TypeVoid) {
if return_args {
func.returns = vec![Types::Void];
} else {
func.args = vec![Types::Void];
return_args = true;
continue;
}
Types::Void
} else
if op.typ == OpType::Instruction(InstructionType::TypeStr) {
Types::Str
} else
if op.typ == OpType::Instruction(InstructionType::TypeAny) {
Types::Any
} else {
panic!()
};
if return_args {
func.returns.push(t);
} else {
func.args.push(t);
}
}
if op.typ == OpType::Instruction(InstructionType::Returns) {
return_args = true;
}
if op.typ == OpType::Keyword(KeywordType::FunctionDo) {
break;
}
p = rtokens.pop();
};
functions.insert(name.clone(), func.clone());
// if name == "main" {
// in_function = (name, func.clone());
// }
if func.args != vec![Types::Void] {
stack.append(&mut func.args);
}
stack_snapshots.push(stack.clone());
}
KeywordType::Else |
KeywordType::End |
KeywordType::While |
KeywordType::Function |
KeywordType::Include |
KeywordType::Constant |
KeywordType::Memory => (),
KeywordType::FunctionDo => (),
}
},
OpType::Instruction(instruction) => {
@@ -76,42 +181,42 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
},
InstructionType::Minus => {
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Int);
},
InstructionType::Plus => {
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Int);
},
InstructionType::Equals => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Bool);
},
InstructionType::Gt => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Bool);
},
InstructionType::Lt => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Bool);
},
InstructionType::Ge => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Bool);
},
InstructionType::Le => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Bool);
},
InstructionType::NotEquals => {
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int, Types::Ptr])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Bool);
},
InstructionType::Band => {
@@ -145,9 +250,6 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
stack_pop(&mut stack, &op, &[Types::Int])?;
stack.push(Types::Int);
},
InstructionType::Mem => {
stack.push(Types::Ptr);
},
InstructionType::Load8 => {
stack_pop(&mut stack, &op, &[Types::Ptr])?;
stack.push(Types::Int);
@@ -233,18 +335,73 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
stack_pop(&mut stack, &op, &[Types::Any])?;
stack.push(Types::Int);
},
InstructionType::CastVoid => {
stack_pop(&mut stack, &op, &[Types::Any])?;
stack.push(Types::Any);
},
InstructionType::MemUse => {
stack.push(Types::Ptr);
},
InstructionType::FnCall |
InstructionType::Return |
InstructionType::FnCall => {
stack_snapshots.push(stack.clone());
let f = functions.get(&op.text).unwrap();
let mut s = stack.clone();
let mut a = f.args.clone();
// s.reverse();
a.reverse();
for t in a{
if let Some(s2) = s.pop(){
if t != s2 {
lerror!(&op.loc, "Expected {:?}, but got {:?}", t, s2);
return Err(eyre!(""));
}
} else {
lerror!(&op.loc, "Expected {:?}, but got nothing", t);
return Err(eyre!(""));
}
}
}
InstructionType::Return => {
let snap = stack_snapshots.pop().unwrap();
// snap.append(&mut f.returns.clone());
let mut st = stack.clone();
for s in snap{
if let Some(sn) = st.pop(){
if s != sn {
lerror!(&op.loc, "Expected {:?}, but got {:?}", s, sn);
return Err(eyre!(""));
}
} else {
lerror!(&op.loc, "Expected {:?}, but got nothing", s);
return Err(eyre!(""));
}
}
}
InstructionType::None => {},
InstructionType::TypeBool |
InstructionType::TypePtr |
InstructionType::TypeInt |
InstructionType::TypeVoid |
InstructionType::TypeAny |
InstructionType::TypeStr |
InstructionType::Returns |
InstructionType::With => (),
InstructionType::ConstUse => todo!(),
}
},
}
}
Ok(ops.to_vec())
}
Ok(ops.clone())
}