something

This commit is contained in:
2024-03-23 02:28:20 +02:00
parent 6ae49ea4c8
commit fe8e9da774
9 changed files with 633 additions and 177 deletions

View File

@@ -3,7 +3,7 @@ mod utils;
use std::path::PathBuf;
use std::{fs::File, io::BufWriter, path::Path};
use std::io::Write;
use crate::types::ast::{AstNode, Function, Module, Program};
use crate::types::ast::{AstNode, EscIdent, Function, MemSize, Module, Program};
use crate::types::token::{InstructionType, Token, TokenType};
use super::utils::run_cmd;
@@ -14,7 +14,8 @@ use super::Compiler;
pub struct X86_64LinuxNasmCompiler {
strings: Vec<String>,
func_mem_i: Vec<usize>,
// func_mem_i: Vec<usize>,
// func_mem_list: HashMap<String, usize>,
if_i: usize,
while_i: usize,
used_consts: Vec<String>
@@ -272,13 +273,10 @@ impl X86_64LinuxNasmCompiler {
InstructionType::CastPtr |
InstructionType::CastInt |
InstructionType::CastVoid => (), //? Possibly have a use for this
InstructionType::TypeBool |
InstructionType::TypePtr |
InstructionType::TypeInt |
InstructionType::TypeVoid |
InstructionType::TypeAny |
InstructionType::FnCall |
InstructionType::MemUse |
InstructionType::StructPath(_) |
InstructionType::StructItem(_) |
InstructionType::ConstUse => unreachable!(),
InstructionType::Return => {
writeln!(fd, " sub rbp, 8")?;
@@ -289,29 +287,26 @@ impl X86_64LinuxNasmCompiler {
}
},
TokenType::Keyword(_) |
TokenType::Type(_) |
TokenType::Unknown(_) => unreachable!(),
}
Ok(())
}
fn handle_module(&mut self, fd: &mut BufWriter<File>, prog: &Program, module: &Module) -> anyhow::Result<()> {
writeln!(fd, "; {} Module {} START", module.path.join("::"), module.ident)?;
writeln!(fd, "; {} Module START", module.path.join("::"))?;
self.handle_ast_list(fd, prog, module.body.clone())?;
writeln!(fd, "; {} Module {} END", module.path.join("::"), module.ident)?;
writeln!(fd, "; {} Module END", module.path.join("::"))?;
Ok(())
}
fn handle_function(&mut self, fd: &mut BufWriter<File>, prog: &Program, func: &Function) -> anyhow::Result<()> {
writeln!(fd, "{f}: ; fn {f}", f=func.ident)?;
writeln!(fd, " pop rbx")?;
writeln!(fd, " mov qword [rbp], rbx")?;
writeln!(fd, " add rbp, 8")?;
writeln!(fd, "{f}: ; fn {f}", f=func.get_ident_escaped())?;
writeln!(fd, " fn_setup")?;
self.handle_ast_list(fd, prog, func.body.clone())?;
writeln!(fd, " sub rbp, 8")?;
writeln!(fd, " mov rbx, qword [rbp]")?;
writeln!(fd, " push rbx")?;
writeln!(fd, " fn_cleanup")?;
writeln!(fd, " ret")?;
Ok(())
}
@@ -355,21 +350,27 @@ impl X86_64LinuxNasmCompiler {
writeln!(fd, "; WHILE({id}) END")?;
},
AstNode::Module(m) => self.handle_module(fd, prog, m)?,
AstNode::Memory(m) => {
if !m.statc {
todo!()
}
AstNode::Memory(_) => {
//? Possibly allow stack based allocation somehow
// if !m.statc {
// todo!()
// }
},
AstNode::MemUse(_) => {
AstNode::MemUse(m) => {
let tmp = if let Some(disp) = m.disp {
format!("+{disp}")
} else {
String::new()
};
writeln!(fd, " push m_{}{}", m.get_ident_escaped(), tmp)?;
},
AstNode::ConstUse(c) => {
self.used_consts.push(c.ident.clone());
writeln!(fd, " mov rax, qword [c_{}]", c.ident)?;
self.used_consts.push(c.get_ident_escaped());
writeln!(fd, " mov rax, qword [c_{}]", c.get_ident_escaped())?;
writeln!(fd, " push rax")?;
},
AstNode::FnCall(f)=> {
writeln!(fd, " call {f} ; FUNCTIONCALL({f:?})", f=f.ident)?;
writeln!(fd, " call {f} ; FUNCTIONCALL({f:?})", f=f.get_ident_escaped())?;
},
AstNode::Block(b)=> {
writeln!(fd, "; BLOCK({}) START", b.comment)?;
@@ -381,6 +382,11 @@ impl X86_64LinuxNasmCompiler {
AstNode::Str(_, _) |
AstNode::CStr(_, _) |
AstNode::Char(_, _) => unreachable!(),
AstNode::StructDef(_) => (),
AstNode::StructDispPush { disp, ident, .. } => {
writeln!(fd, " mov rax, {} ; STRUCTDISPPUSH({})", disp, ident)?;
writeln!(fd, " push rax")?;
},
}
}
Ok(())
@@ -395,6 +401,8 @@ impl Compiler for X86_64LinuxNasmCompiler {
used_consts: Vec::new(),
if_i: 0,
while_i: 0,
// func_mem_i: Vec::new(),
// func_mem_list: HashMap::new(),
}
}
@@ -402,6 +410,18 @@ impl Compiler for X86_64LinuxNasmCompiler {
writeln!(fd, "BITS 64")?;
writeln!(fd, "segment .text")?;
writeln!(fd, "%macro fn_setup 0")?;
writeln!(fd, " pop rbx")?;
writeln!(fd, " mov qword [rbp], rbx")?;
writeln!(fd, " add rbp, 8")?;
writeln!(fd, "%endmacro")?;
writeln!(fd, "%macro fn_cleanup 0")?;
writeln!(fd, " sub rbp, 8")?;
writeln!(fd, " mov rbx, qword [rbp]")?;
writeln!(fd, " push rbx")?;
writeln!(fd, "%endmacro")?;
writeln!(fd, "{}", utils::DBG_PRINT)?;
writeln!(fd, "global _start")?;
writeln!(fd, "_start:")?;
@@ -425,22 +445,22 @@ impl Compiler for X86_64LinuxNasmCompiler {
writeln!(fd, "segment .data")?;
for (_, v) in prog.constants.iter() {
if !self.used_consts.contains(&v.ident) {
if !self.used_consts.contains(&v.get_ident_escaped()) {
continue;
}
match Box::leak(v.value.clone()) {
AstNode::Int(_, val) => {
writeln!(fd, "c_{}: dq {}", v.ident, val)?;
writeln!(fd, " c_{}: dq {}", v.get_ident_escaped(), val)?;
}
AstNode::Str(_, val) |
AstNode::CStr(_, val) => {
let s_chars = val.chars().map(|c| (c as u32).to_string()).collect::<Vec<String>>();
let s_list = s_chars.join(",");
writeln!(fd, "c_{}: db {} ; {}", v.ident, s_list, val.escape_debug())?;
writeln!(fd, " c_{}: db {} ; {}", v.get_ident_escaped(), s_list, val.escape_debug())?;
}
AstNode::Char(_, val) => {
writeln!(fd, "c_{}: db {} ; '{}'", v.ident, *val as u8, val)?;
writeln!(fd, " c_{}: db {} ; '{}'", v.get_ident_escaped(), *val as u8, val)?;
}
c => panic!("{c:?}")
};
@@ -449,12 +469,21 @@ impl Compiler for X86_64LinuxNasmCompiler {
for (i, s) in self.strings.iter().enumerate() {
let s_chars = s.chars().map(|c| (c as u32).to_string()).collect::<Vec<String>>();
let s_list = s_chars.join(",");
writeln!(fd, "str_{i}: db {} ; STRDEF({})", s_list, s.escape_debug())?;
writeln!(fd, " str_{i}: db {} ; STRDEF({})", s_list, s.escape_debug())?;
}
writeln!(fd, "segment .bss")?;
writeln!(fd, "ret_stack: resq 256")?;
writeln!(fd, " ret_stack: resq 256")?;
//TODO: Memories
for (_, v) in &prog.memories {
match &v.size {
MemSize::Size(s) => {
writeln!(fd, " m_{}: resb {}", v.get_ident_escaped(), s)?;
},
MemSize::Type(tt) => {
writeln!(fd, " m_{}: resb {} ; {:?}", v.get_ident_escaped(), tt.get_size(), tt)?;
},
}
}
Ok(())

View File

@@ -1,7 +1,7 @@
use std::path::Path;
use anyhow::bail;
use crate::{error, types::{common::Loc, token::{InstructionType, KeywordType, Token, TokenType}}};
use crate::{error, types::{common::Loc, token::{InstructionType, KeywordType, Token, TokenType, TypeType}}};
@@ -135,6 +135,88 @@ impl Lexer {
self.tokens.push(Token::new(TokenType::Instruction(InstructionType::PushStr(str)), self.loc(), buf.clone()));
buf.clear();
}
':' if chars.get(idx + 1) == Some(&':') => {
let mut p_buf = vec![buf.clone()];
buf.clear();
idx += 2; // skip ::
self.loc.col += 2;
while idx < chars.len() {
match chars[idx] {
' ' | '\n' | '\r' => {
if !p_buf.is_empty() {
p_buf.push(buf.clone());
}
self.tokens.push(Token::new(TokenType::Instruction(InstructionType::StructPath(p_buf.clone())), start_loc.clone(), p_buf.clone().join("::")));
buf.clear();
break;
}
c @ ('\'' | '"') => {
error!({loc => self.loc()}, "Invalid char in struct path token, expected /a-z|A-Z|0-9|_|-/ got {c}");
bail!("")
}
':' if chars.get(idx + 1) == Some(&':') => {
if buf.is_empty() {
error!({loc => self.loc()}, "Invalid char in struct path token, expected /a-z|A-Z|0-9|_|-/ got '.'");
bail!("")
}
idx += 2; // skip ::
self.loc.col += 2;
p_buf.push(buf.clone());
buf.clear();
}
c => {
buf.push(c);
idx += 1;
self.loc.inc_col();
}
}
}
}
'.' if !buf.is_empty() => {
let mut p_buf = vec![buf.clone()];
buf.clear();
idx += 1; // skip .
self.loc.inc_col();
while idx < chars.len() {
match chars[idx] {
' ' | '\n' | '\r' => {
if !p_buf.is_empty() {
p_buf.push(buf.clone());
}
self.tokens.push(Token::new(TokenType::Instruction(InstructionType::StructItem(p_buf.clone())), start_loc.clone(), p_buf.clone().join(".")));
buf.clear();
break;
}
c @ ('\'' | '"') => {
error!({loc => self.loc()}, "Invalid char in struct access token, expected /a-z|A-Z|0-9|_|-/ got {c}");
bail!("")
}
'.' => {
if buf.is_empty() {
error!({loc => self.loc()}, "Invalid char in struct access token, expected /a-z|A-Z|0-9|_|-/ got '.'");
bail!("")
}
idx += 1; // skip .
self.loc.col += 1;
p_buf.push(buf.clone());
buf.clear();
}
c => {
buf.push(c);
idx += 1;
self.loc.inc_col();
}
}
}
}
ch @ (' ' | '\n' | '\r') => {
if ch == '\n' {
@@ -219,66 +301,69 @@ impl Lexer {
fn match_token_type(&self, s: &str) -> TokenType {
match s {
"if" => TokenType::Keyword(KeywordType::If),
"else" => TokenType::Keyword(KeywordType::Else),
"end" => TokenType::Keyword(KeywordType::End),
"while" => TokenType::Keyword(KeywordType::While),
"do" => TokenType::Keyword(KeywordType::Do),
"include" => TokenType::Keyword(KeywordType::Include),
"memory" => TokenType::Keyword(KeywordType::Memory),
"const" => TokenType::Keyword(KeywordType::Constant),
"fn" => TokenType::Keyword(KeywordType::Function),
"then" => TokenType::Keyword(KeywordType::Then),
"done" => TokenType::Keyword(KeywordType::Done),
"struct" => TokenType::Keyword(KeywordType::Struct),
"inline" => TokenType::Keyword(KeywordType::Inline),
"export" => TokenType::Keyword(KeywordType::Export),
"extern" => TokenType::Keyword(KeywordType::Extern),
"returns" => TokenType::Keyword(KeywordType::Returns),
"with" => TokenType::Keyword(KeywordType::With),
"drop" => TokenType::Instruction(InstructionType::Drop),
"_dbg_print"=> TokenType::Instruction(InstructionType::Print),
"dup" => TokenType::Instruction(InstructionType::Dup),
"rot" => TokenType::Instruction(InstructionType::Rot),
"over" => TokenType::Instruction(InstructionType::Over),
"swap" => TokenType::Instruction(InstructionType::Swap),
"sub" => TokenType::Instruction(InstructionType::Minus),
"add" => TokenType::Instruction(InstructionType::Plus),
"eq" => TokenType::Instruction(InstructionType::Equals),
"gt" => TokenType::Instruction(InstructionType::Gt),
"lt" => TokenType::Instruction(InstructionType::Lt),
"ge" => TokenType::Instruction(InstructionType::Ge),
"le" => TokenType::Instruction(InstructionType::Le),
"neq" => TokenType::Instruction(InstructionType::NotEquals),
"band" => TokenType::Instruction(InstructionType::Band),
"bor" => TokenType::Instruction(InstructionType::Bor),
"shr" => TokenType::Instruction(InstructionType::Shr),
"shl" => TokenType::Instruction(InstructionType::Shl),
"divmod" => TokenType::Instruction(InstructionType::DivMod),
"mul" => TokenType::Instruction(InstructionType::Mul),
"read8" => TokenType::Instruction(InstructionType::Read8),
"write8" => TokenType::Instruction(InstructionType::Write8),
"read32" => TokenType::Instruction(InstructionType::Read32),
"write32" => TokenType::Instruction(InstructionType::Write32),
"read64" => TokenType::Instruction(InstructionType::Read64),
"write64" => TokenType::Instruction(InstructionType::Write64),
"syscall0" => TokenType::Instruction(InstructionType::Syscall0),
"syscall1" => TokenType::Instruction(InstructionType::Syscall1),
"syscall2" => TokenType::Instruction(InstructionType::Syscall2),
"syscall3" => TokenType::Instruction(InstructionType::Syscall3),
"syscall4" => TokenType::Instruction(InstructionType::Syscall4),
"syscall5" => TokenType::Instruction(InstructionType::Syscall5),
"syscall6" => TokenType::Instruction(InstructionType::Syscall6),
"(bool)" => TokenType::Instruction(InstructionType::CastBool),
"(ptr)" => TokenType::Instruction(InstructionType::CastPtr),
"(int)" => TokenType::Instruction(InstructionType::CastInt),
"(void)" => TokenType::Instruction(InstructionType::CastVoid),
"bool" => TokenType::Instruction(InstructionType::TypeBool),
"ptr" => TokenType::Instruction(InstructionType::TypePtr),
"int" => TokenType::Instruction(InstructionType::TypeInt),
"void" => TokenType::Instruction(InstructionType::TypeVoid),
"any" => TokenType::Instruction(InstructionType::TypeAny),
"return" => TokenType::Instruction(InstructionType::Return),
"if" => TokenType::Keyword(KeywordType::If),
"else" => TokenType::Keyword(KeywordType::Else),
"end" => TokenType::Keyword(KeywordType::End),
"while" => TokenType::Keyword(KeywordType::While),
"do" => TokenType::Keyword(KeywordType::Do),
"include" => TokenType::Keyword(KeywordType::Include),
"memory" => TokenType::Keyword(KeywordType::Memory),
"const" => TokenType::Keyword(KeywordType::Constant),
"fn" => TokenType::Keyword(KeywordType::Function),
"then" => TokenType::Keyword(KeywordType::Then),
"done" => TokenType::Keyword(KeywordType::Done),
"typedef" => TokenType::Keyword(KeywordType::TypeDef),
"structdef" => TokenType::Keyword(KeywordType::StructDef),
"inline" => TokenType::Keyword(KeywordType::Inline),
"export" => TokenType::Keyword(KeywordType::Export),
"extern" => TokenType::Keyword(KeywordType::Extern),
"returns" => TokenType::Keyword(KeywordType::Returns),
"with" => TokenType::Keyword(KeywordType::With),
"drop" => TokenType::Instruction(InstructionType::Drop),
"_dbg_print" => TokenType::Instruction(InstructionType::Print),
"dup" => TokenType::Instruction(InstructionType::Dup),
"rot" => TokenType::Instruction(InstructionType::Rot),
"over" => TokenType::Instruction(InstructionType::Over),
"swap" => TokenType::Instruction(InstructionType::Swap),
"sub" => TokenType::Instruction(InstructionType::Minus),
"add" => TokenType::Instruction(InstructionType::Plus),
"eq" => TokenType::Instruction(InstructionType::Equals),
"gt" => TokenType::Instruction(InstructionType::Gt),
"lt" => TokenType::Instruction(InstructionType::Lt),
"ge" => TokenType::Instruction(InstructionType::Ge),
"le" => TokenType::Instruction(InstructionType::Le),
"neq" => TokenType::Instruction(InstructionType::NotEquals),
"band" => TokenType::Instruction(InstructionType::Band),
"bor" => TokenType::Instruction(InstructionType::Bor),
"shr" => TokenType::Instruction(InstructionType::Shr),
"shl" => TokenType::Instruction(InstructionType::Shl),
"divmod" => TokenType::Instruction(InstructionType::DivMod),
"mul" => TokenType::Instruction(InstructionType::Mul),
"read8" => TokenType::Instruction(InstructionType::Read8),
"write8" => TokenType::Instruction(InstructionType::Write8),
"read32" => TokenType::Instruction(InstructionType::Read32),
"write32" => TokenType::Instruction(InstructionType::Write32),
"read64" => TokenType::Instruction(InstructionType::Read64),
"write64" => TokenType::Instruction(InstructionType::Write64),
"syscall0" => TokenType::Instruction(InstructionType::Syscall0),
"syscall1" => TokenType::Instruction(InstructionType::Syscall1),
"syscall2" => TokenType::Instruction(InstructionType::Syscall2),
"syscall3" => TokenType::Instruction(InstructionType::Syscall3),
"syscall4" => TokenType::Instruction(InstructionType::Syscall4),
"syscall5" => TokenType::Instruction(InstructionType::Syscall5),
"syscall6" => TokenType::Instruction(InstructionType::Syscall6),
"(bool)" => TokenType::Instruction(InstructionType::CastBool),
"(ptr)" => TokenType::Instruction(InstructionType::CastPtr),
"(int)" => TokenType::Instruction(InstructionType::CastInt),
"(void)" => TokenType::Instruction(InstructionType::CastVoid),
"return" => TokenType::Instruction(InstructionType::Return),
"ptr" => TokenType::Type(TypeType::Ptr),
"u8" => TokenType::Type(TypeType::U8),
"u16" => TokenType::Type(TypeType::U16),
"u32" => TokenType::Type(TypeType::U32),
"u64" => TokenType::Type(TypeType::U64),
"void" => TokenType::Type(TypeType::Void),
"any" => TokenType::Type(TypeType::Any),
t => TokenType::Unknown(t.to_string())
}
}

View File

@@ -6,7 +6,7 @@ use std::{collections::HashMap, path::Path};
use anyhow::{bail, Result};
use crate::{cli::CliArgs, lexer::Lexer, types::{ast::{AstNode, Block, ConstUse, Constant, FnCall, Function, If, MemUse, Memory, Module, Program, While}, common::Loc, token::{InstructionType, KeywordType, Token, TokenType}}};
use crate::{cli::CliArgs, lexer::Lexer, types::{ast::{AstNode, Block, ConstUse, Constant, FnCall, Function, If, MemSize, MemUse, Memory, Module, Program, StructDef, While}, common::Loc, token::{InstructionType, KeywordType, Token, TokenType, TypeType}}};
use self::{builtin::get_builtin_symbols, precompiler::{precompile_const, precompile_mem}, utils::{expect, peek_check, peek_check_multiple, PeekResult}};
@@ -16,6 +16,7 @@ bitflags::bitflags! {
const EXTERN = 1 << 0;
const EXPORT = 1 << 1;
const INLINE = 1 << 2;
const ALLOW_TYPES = 1 << 3;
}
}
@@ -35,7 +36,7 @@ pub fn parse(cli_args: &CliArgs, tokens: &mut Vec<Token>) -> Result<Program> {
functions: HashMap::new(),
constants: HashMap::new(),
memories: HashMap::new(),
struct_defs: HashMap::new()
};
let syms = get_builtin_symbols(&mut prog);
@@ -67,16 +68,17 @@ fn parse_next(cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, f
let ret = match &token.typ {
TokenType::Keyword(kw) => {
match kw {
KeywordType::If => parse_if(&token, cli_args, prog, tokens)?,
KeywordType::While => parse_while(&token, cli_args, prog, tokens)?,
KeywordType::Include => parse_include(&token, cli_args, prog, tokens)?,
KeywordType::Memory => parse_memory(&token, cli_args, prog, tokens, is_module_root)?,
KeywordType::Constant => parse_const(&token, cli_args, prog, tokens)?,
KeywordType::Function => parse_function(&token, cli_args, prog, tokens, flags)?,
KeywordType::Struct => todo!(),
KeywordType::Inline => parse_inline(&token, cli_args, prog, tokens, flags)?,
KeywordType::Export => parse_export(&token, cli_args, prog, tokens, flags)?,
KeywordType::Extern => parse_extern(&token, cli_args, prog, tokens, flags)?,
KeywordType::If => parse_if(&token, cli_args, prog, tokens)?,
KeywordType::While => parse_while(&token, cli_args, prog, tokens)?,
KeywordType::Include => parse_include(&token, cli_args, prog, tokens)?,
KeywordType::Memory => parse_memory(&token, cli_args, prog, tokens, is_module_root)?,
KeywordType::Constant => parse_const(&token, cli_args, prog, tokens)?,
KeywordType::Function => parse_function(&token, cli_args, prog, tokens, flags)?,
KeywordType::StructDef => parse_struct(&token, cli_args, prog, tokens)?,
KeywordType::TypeDef => todo!(),
KeywordType::Inline => parse_inline(&token, cli_args, prog, tokens, flags)?,
KeywordType::Export => parse_export(&token, cli_args, prog, tokens, flags)?,
KeywordType::Extern => parse_extern(&token, cli_args, prog, tokens, flags)?,
kw => {
dbg!(&prog.constants);
error!({loc => token.loc}, "Unexpected token {kw:?}");
@@ -89,7 +91,11 @@ fn parse_next(cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, f
error!({loc => token.loc}, "Unexpected token {it:?}, please create a main function, this is not a scripting language");
bail!("")
} else {
AstNode::Token(token)
match it {
InstructionType::StructPath(p) => parse_struct_path(&token, prog, p)?,
InstructionType::StructItem(p) => parse_struct_item(&token, prog, p)?,
_ => AstNode::Token(token)
}
}
},
TokenType::Unknown(ut) => {
@@ -101,10 +107,162 @@ fn parse_next(cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, f
parse_unknown(&token, cli_args, prog, tokens, flags)?
}
},
TokenType::Type(t) => {
if flags.contains(Flags::ALLOW_TYPES) {
AstNode::Token(token)
} else {
error!({loc => token.loc}, "Unexpected type {t:?}");
bail!("")
}
},
};
Ok(ret)
}
fn parse_struct_item(org: &Token, prog: &mut Program, p: &Vec<String>) -> Result<AstNode> {
fn find_disp(strct: &StructDef, disp: &mut usize, path: &[String]) {
let Some(p) = path.get(0) else {
return
};
for item in &strct.body {
if p == &item.0 {
match &item.2 {
TypeType::Struct(strct) => {
*disp += item.1;
find_disp(strct, disp, &path[1..])
},
_ => {
*disp += item.1;
}
}
}
}
}
if let Some(mem) = prog.memories.get(&p[0].to_string()) {
match &mem.size {
MemSize::Size(_) => {
error!({loc => org.loc()}, "You can only access items in structs");
bail!("")
},
MemSize::Type(t) => {
match t {
TypeType::Struct(s) => {
let mut disp = 0;
find_disp(&s, &mut disp, &p[1..]);
return Ok(AstNode::MemUse(MemUse{
ident: p[0].clone(),
loc: org.loc(),
disp: Some(disp)
}));
},
_ => {
error!({loc => org.loc()}, "You can only access items in structs");
bail!("")
}
}
},
}
}
error!("Failed to find memory {}", p[0]);
bail!("")
}
fn parse_struct_path(org: &Token, prog: &mut Program, p: &Vec<String>) -> Result<AstNode> {
fn find_disp(strct: &StructDef, disp: &mut usize, path: &[String]) {
let Some(p) = path.get(0) else {
return
};
for item in &strct.body {
if p == &item.0 {
match &item.2 {
TypeType::Struct(strct) => {
*disp += item.1;
find_disp(strct, disp, &path[1..])
},
_ => {
*disp += item.1;
}
}
}
}
}
let mut disp = 0;
if let Some(strct) = prog.struct_defs.get(&p[0].to_string()) {
find_disp(strct, &mut disp, &p[1..]);
return Ok(AstNode::StructDispPush{
ident: org.lexem.clone(),
loc: org.loc(),
disp
});
}
error!("Failed to find struct {}", p[0]);
bail!("")
}
fn parse_struct(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>) -> Result<AstNode> {
let ident = expect(tokens, TokenType::Unknown(String::new()))?;
expect(tokens, TokenType::Keyword(KeywordType::Do))?;
let mut body: Vec<(String, usize, TypeType)> = Vec::new();
let mut size = 0;
loop {
let ident = expect(tokens, TokenType::Unknown(String::new()))?;
expect(tokens, TokenType::Keyword(KeywordType::Do))?;
let typ = parse_next(cli_args, prog, tokens, Flags::ALLOW_TYPES, false)?;
let (typ, disp) = match &typ {
AstNode::Token(t) => {
match &t.typ {
TokenType::Type(t) => {
let disp = size;
size += t.get_size();
(t, disp)
}
_ => {
error!({loc => t.loc()}, "Expected type, got {t:?}");
bail!("")
}
}
},
t => {
error!({loc => typ.loc()}, "Expected type, got {t:?}");
bail!("")
}
};
expect(tokens, TokenType::Keyword(KeywordType::End))?;
body.push((ident.lexem, disp, typ.clone()));
if peek_check(tokens, TokenType::Keyword(KeywordType::Done)).correct(){
tokens.pop();
break;
}
// if peek_check(tokens, TokenType::Keyword(KeywordType::End)).correct()
};
let def = StructDef{
loc: org.loc(),
ident: ident.lexem.clone(),
body,
size,
};
prog.struct_defs.insert(ident.lexem, def.clone());
Ok(AstNode::StructDef(def))
}
fn parse_memory(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, is_module_root: bool) -> Result<AstNode> {
let name = expect(tokens, TokenType::Unknown(String::new()))?;
@@ -118,7 +276,7 @@ fn parse_memory(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mu
PeekResult::Wrong(_) => (),
PeekResult::None => panic!("idk what to do herre"),
}
body.push(parse_next(cli_args, prog, tokens, Flags::empty(), false)?);
body.push(parse_next(cli_args, prog, tokens, Flags::ALLOW_TYPES, false)?);
}
expect(tokens, TokenType::Keyword(KeywordType::End))?;
@@ -152,13 +310,21 @@ fn parse_function(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &
loop {
if let PeekResult::Correct(t) = peek_check_multiple(tokens, vec![
TokenType::Instruction(InstructionType::TypeAny),
TokenType::Instruction(InstructionType::TypeBool),
TokenType::Instruction(InstructionType::TypeInt),
TokenType::Instruction(InstructionType::TypePtr),
TokenType::Instruction(InstructionType::TypeVoid),
TokenType::Type(TypeType::Any),
TokenType::Type(TypeType::U8),
TokenType::Type(TypeType::U16),
TokenType::Type(TypeType::U32),
TokenType::Type(TypeType::U64),
TokenType::Type(TypeType::Ptr),
TokenType::Type(TypeType::Void),
TokenType::Type(TypeType::Custom(Vec::new())),
]) {
args.push(t.typ.clone());
match &t.typ {
TokenType::Type(tt) => {
args.push(tt.clone());
}
_ => unreachable!()
}
} else {
break;
}
@@ -171,13 +337,21 @@ fn parse_function(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &
loop {
if let PeekResult::Correct(t) = peek_check_multiple(tokens, vec![
TokenType::Instruction(InstructionType::TypeAny),
TokenType::Instruction(InstructionType::TypeBool),
TokenType::Instruction(InstructionType::TypeInt),
TokenType::Instruction(InstructionType::TypePtr),
TokenType::Instruction(InstructionType::TypeVoid),
TokenType::Type(TypeType::Any),
TokenType::Type(TypeType::U8),
TokenType::Type(TypeType::U16),
TokenType::Type(TypeType::U32),
TokenType::Type(TypeType::U64),
TokenType::Type(TypeType::Ptr),
TokenType::Type(TypeType::Void),
TokenType::Type(TypeType::Custom(Vec::new())),
]) {
ret_args.push(t.typ.clone());
match &t.typ {
TokenType::Type(tt) => {
ret_args.push(tt.clone());
}
_ => unreachable!()
}
} else {
break;
}
@@ -235,7 +409,7 @@ fn parse_if(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Ve
PeekResult::Wrong(w) => {
match w.typ {
TokenType::Keyword(KeywordType::Then) => {
warn!("If is defined as `if ... do ... done`");
warn!({loc => w.loc()}, "If is defined as `if ... do ... done`");
}
_ => ()
}
@@ -502,6 +676,7 @@ fn parse_include(_: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut
functions: prog.functions.clone(),
constants: prog.constants.clone(),
memories: prog.memories.clone(),
struct_defs: prog.struct_defs.clone(),
};
@@ -563,7 +738,7 @@ fn parse_const(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut
fn parse_unknown(org: &Token, _: &CliArgs, prog: &mut Program, _: &mut Vec<Token>, _: Flags ) -> Result<AstNode> {
//TODO: Typing?
if let Some(func) = prog.functions.get(&org.lexem) {
if let Some(func) = prog.functions.get(&org.lexem.clone()) {
if func.inline {
return Ok(AstNode::Block(Block{ loc: org.loc.clone(), body: func.body.clone(), comment: format!("inline fn {}", func.ident) }))
} else {
@@ -571,15 +746,42 @@ fn parse_unknown(org: &Token, _: &CliArgs, prog: &mut Program, _: &mut Vec<Token
}
}
if let Some(_) = prog.constants.get(&org.lexem) {
if let Some(_) = prog.constants.get(&org.lexem.clone()) {
return Ok(AstNode::ConstUse(ConstUse{ loc: org.loc.clone(), ident: org.lexem.clone() }));
}
if let Some(_) = prog.memories.get(&org.lexem) {
return Ok(AstNode::MemUse(MemUse{ loc: org.loc.clone(), ident: org.lexem.clone() }));
if let Some(_) = prog.memories.get(&org.lexem.clone()) {
return Ok(AstNode::MemUse(MemUse{ loc: org.loc.clone(), ident: org.lexem.clone(), disp: None }));
}
dbg!(&prog.constants);
if let Some(t) = prog.struct_defs.get(&org.lexem.clone()) {
return Ok(AstNode::Token(Token {
typ: TokenType::Type(TypeType::Struct(t.clone())),
loc: org.loc(),
lexem: org.lexem.clone(),
}));
}
// if org.lexem.clone().contains("::") {
// let pth = org.lexem.clone();
// let pth = pth.split("::").collect::<Vec<&str>>();
// dbg!(prog.struct_defs.clone());
// if let Some(t) = prog.struct_defs.get(&pth[0].to_string()) {
// if let Some(i) = t.body.iter().find(|i| i.0 == pth[1].to_string()) {
// return Ok(AstNode::StructDispPush{
// ident: org.lexem.clone(),
// loc: org.loc(),
// disp: i.1
// });
// }
// }
// }
// dbg!(&prog.constants);
debug!({loc => org.loc.clone()}, "Unknown token");
error!({loc => org.loc.clone()}, "Unknown token {:?}", org);
bail!("")
}

View File

@@ -1,17 +1,56 @@
use anyhow::bail;
use crate::types::{ast::{AstNode, Program}, common::Loc, token::{InstructionType, TokenType}};
use crate::types::{ast::{AstNode, MemSize, Program}, common::Loc, token::{InstructionType, TokenType, TypeType}};
pub fn precompile_mem(prog: &Program, ast: Vec<AstNode> ) -> anyhow::Result<usize> {
pub fn precompile_mem(prog: &Program, ast: Vec<AstNode> ) -> anyhow::Result<MemSize> {
match &ast[0] {
AstNode::Token(t) => {
match &t.typ {
TokenType::Type(_) => {
let mut buf = vec![];
let mut i = 0;
while ast.len() > i {
match &ast[i] {
AstNode::Token(t) => {
match &t.typ {
TokenType::Type(t) => {
match t {
TypeType::Struct(s) => {
return Ok(MemSize::Type(TypeType::Struct(s.clone())));
},
_ => ()
}
buf.push(t.clone());
i += 1;
}
_ => {
error!({loc => t.loc()}, "Cannot use a type and a number as a memory size at the same time");
bail!("")
}
}
},
_ => {
error!({loc => t.loc()}, "Cannot use a type and a number as a memory size at the same time");
bail!("")
}
}
}
return Ok(MemSize::Type(TypeType::Custom(buf)));
}
_ => ()
}
},
_ => (),
}
match precompile_const(prog, ast, &mut Vec::new()) {
Ok(v) => {
match v {
AstNode::Int(_, i) => {
return Ok(i)
return Ok(MemSize::Size(i))
}
_ => {
error!("memories can only have numbers or types in their size");
error!({loc => v.loc()}, "Can only have a type or a number as a memory size");
bail!("")
}
}
@@ -142,7 +181,11 @@ pub fn precompile_const(prog: &Program, ast: Vec<AstNode>, stack: &mut Vec<usize
}
}
},
TokenType::Unknown(_) => todo!(),
TokenType::Unknown(_) => unreachable!(),
TokenType::Type(_) => {
error!({loc => t.loc()}, "Cannot use a type and a number as a memory size at the same time");
bail!("")
},
}
},
//TODO: Implement these

View File

@@ -41,6 +41,9 @@ pub fn cmp(lhs: &TokenType, rhs: &TokenType) -> bool {
(TokenType::Instruction(lhs), TokenType::Instruction(rhs)) => {
std::mem::discriminant(lhs) == std::mem::discriminant(rhs)
},
(TokenType::Type(lhs), TokenType::Type(rhs)) => {
std::mem::discriminant(lhs) == std::mem::discriminant(rhs)
},
(TokenType::Unknown(_), TokenType::Unknown(_)) => true,
_ => false
}
@@ -50,7 +53,7 @@ pub fn peek_check_multiple(tokens: &Vec<Token>, typs: Vec<TokenType>) -> PeekRes
let t = tokens.last();
if let Some(t) = t {
for tt in typs {
for tt in typs.clone() {
if cmp(&t.typ, &tt) {
return PeekResult::Correct(t);
}
@@ -86,7 +89,7 @@ pub fn expect(tokens: &mut Vec<Token>, typ: TokenType) -> Result<Token> {
Some(t) => {
//? Source: https://doc.rust-lang.org/std/mem/fn.discriminant.html
if std::mem::discriminant(&t.typ) != std::mem::discriminant(&typ) {
error!("Expected {:?}, but got {:?}", typ, t.typ);
error!({loc => t.loc()}, "Expected {:?}, but got {:?}", typ, t.typ);
bail!("")
}
Ok(t)

View File

@@ -1,6 +1,6 @@
use std::collections::HashMap;
use super::{common::Loc, token::{Token, TokenType}};
use super::{common::Loc, token::{Token, TypeType}};
//TODO: Implement missing stuff
@@ -23,17 +23,23 @@ pub enum AstNode {
// ident: String,
// value: InstructionType
// },
// Struct{
// loc: Loc,
// ident: String,
// body: Vec<(String, usize)> // (field ident, size in bytes)
// },
// StructDef{
// loc: Loc,
// extrn: bool,
// ident: String,
// body: Vec<(String, usize)> // (field ident, size in bytes)
// },
StructDef(StructDef),
StructDispPush{
loc: Loc,
disp: usize,
ident: String,
},
// StructItemPush{
// loc: Loc,
// disp: usize,
// ident: String,
// },
If(If),
While(While),
Module(Module),
@@ -63,14 +69,25 @@ impl AstNode {
AstNode::Str(loc, _) => loc.clone(),
AstNode::CStr(loc, _) => loc.clone(),
AstNode::Char(loc, _) => loc.clone(),
AstNode::StructDef(s) => s.loc.clone(),
AstNode::StructDispPush { loc, ..} => loc.clone(),
// AstNode::StructItemPush { loc, .. } => loc.clone(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct StructDef {
pub loc: Loc,
pub ident: String,
pub body: Vec<(String, usize, TypeType)>, // (field ident, size in bytes)
pub size: usize
}
#[derive(Debug, Clone)]
pub struct MemUse {
pub loc: Loc,
pub ident: String,
pub disp: Option<usize>
}
#[derive(Debug, Clone)]
pub struct ConstUse {
@@ -119,8 +136,8 @@ pub struct Function {
pub inline: bool,
pub extrn: bool,
pub export: bool,
pub arg_types: Vec<TokenType>,
pub ret_types: Vec<TokenType>,
pub arg_types: Vec<TypeType>,
pub ret_types: Vec<TypeType>,
pub body: Vec<AstNode>
}
@@ -136,7 +153,7 @@ pub struct Memory {
pub loc: Loc,
pub ident: String,
pub statc: bool,
pub size: usize // bytes
pub size: MemSize // bytes
}
@@ -146,6 +163,31 @@ pub struct Program {
pub functions: HashMap<String, Function>,
pub constants: HashMap<String, Constant>,
pub memories: HashMap<String, Memory>,
pub struct_defs: HashMap<String, StructDef>,
}
#[derive(Debug, Clone)]
pub enum MemSize {
Size(usize),
Type(TypeType)
}
impl EscIdent for FnCall {
fn ident(&self) -> String {
self.ident.clone()
}
}
impl EscIdent for ConstUse {
fn ident(&self) -> String {
self.ident.clone()
}
}
impl EscIdent for MemUse {
fn ident(&self) -> String {
self.ident.clone()
}
}
impl EscIdent for Constant {

View File

@@ -1,6 +1,6 @@
#![allow(dead_code)]
use super::common::Loc;
use super::{ast::StructDef, common::Loc};
#[derive(Debug, Clone, PartialEq)]
pub enum InstructionType {
@@ -10,6 +10,8 @@ pub enum InstructionType {
PushStr(String),
PushCStr(String),
PushChar(char),
StructPath(Vec<String>), // foo::bar
StructItem(Vec<String>), // foo.bar
Drop,
Print,
Dup,
@@ -55,14 +57,6 @@ pub enum InstructionType {
CastPtr,
CastInt,
CastVoid,
// typing
TypeBool,
TypePtr,
TypeInt,
TypeVoid,
// TypeStr,
TypeAny,
FnCall,
MemUse,
@@ -83,7 +77,8 @@ pub enum KeywordType {
Function,
Then,
Done,
Struct,
StructDef,
TypeDef,
Inline,
Export,
Extern,
@@ -91,9 +86,56 @@ pub enum KeywordType {
With,
}
#[derive(Clone, PartialEq)]
pub enum TypeType {
Ptr,
U8,
U16,
U32,
U64,
Void,
Any,
Custom(Vec<TypeType>),
Struct(StructDef)
}
impl TypeType {
pub fn get_size(&self) -> usize {
match self {
TypeType::Ptr => std::mem::size_of::<*const ()>(),
TypeType::U8 => 1,
TypeType::U16 => 2,
TypeType::U32 => 4,
TypeType::U64 => 8,
TypeType::Void => 0,
TypeType::Any => 0,
TypeType::Custom(ts) => ts.iter().map(|f| f.get_size()).sum(),
TypeType::Struct(s) => s.size,
}
}
}
impl std::fmt::Debug for TypeType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Ptr => write!(f, "Ptr"),
Self::U8 => write!(f, "U8"),
Self::U16 => write!(f, "U16"),
Self::U32 => write!(f, "U32"),
Self::U64 => write!(f, "U64"),
Self::Void => write!(f, "Void"),
Self::Any => write!(f, "Any"),
Self::Custom(arg0) => f.debug_tuple("Custom").field(arg0).finish(),
Self::Struct(arg0) => write!(f, "{} {}{:?}", arg0.size, arg0.ident, arg0.body),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum TokenType {
Keyword(KeywordType),
Type(TypeType),
Instruction(InstructionType),
Unknown(String)
}