something

This commit is contained in:
Gvidas Juknevičius 2024-03-23 02:28:20 +02:00
parent 6ae49ea4c8
commit fe8e9da774
Signed by: MCorange
GPG Key ID: 12B1346D720B7FBB
9 changed files with 633 additions and 177 deletions

View File

@ -1,14 +1,14 @@
fn fwrite with int ptr int returns int then fn fwrite with u64 ptr u64 returns u64 then
SYS_write syscall3 SYS_write syscall3
done done
fn puts with int ptr int returns int then fn puts with u64 ptr u64 returns u64 then
STDOUT fwrite drop STDOUT fwrite drop
done done
fn eputs with int ptr int returns int then fn eputs with u64 ptr u64 returns u64 then
STDERR fwrite drop STDERR fwrite drop
done done

View File

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

View File

@ -1,7 +1,7 @@
use std::path::Path; use std::path::Path;
use anyhow::bail; 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())); self.tokens.push(Token::new(TokenType::Instruction(InstructionType::PushStr(str)), self.loc(), buf.clone()));
buf.clear(); 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') => { ch @ (' ' | '\n' | '\r') => {
if ch == '\n' { if ch == '\n' {
@ -230,7 +312,8 @@ impl Lexer {
"fn" => TokenType::Keyword(KeywordType::Function), "fn" => TokenType::Keyword(KeywordType::Function),
"then" => TokenType::Keyword(KeywordType::Then), "then" => TokenType::Keyword(KeywordType::Then),
"done" => TokenType::Keyword(KeywordType::Done), "done" => TokenType::Keyword(KeywordType::Done),
"struct" => TokenType::Keyword(KeywordType::Struct), "typedef" => TokenType::Keyword(KeywordType::TypeDef),
"structdef" => TokenType::Keyword(KeywordType::StructDef),
"inline" => TokenType::Keyword(KeywordType::Inline), "inline" => TokenType::Keyword(KeywordType::Inline),
"export" => TokenType::Keyword(KeywordType::Export), "export" => TokenType::Keyword(KeywordType::Export),
"extern" => TokenType::Keyword(KeywordType::Extern), "extern" => TokenType::Keyword(KeywordType::Extern),
@ -273,12 +356,14 @@ impl Lexer {
"(ptr)" => TokenType::Instruction(InstructionType::CastPtr), "(ptr)" => TokenType::Instruction(InstructionType::CastPtr),
"(int)" => TokenType::Instruction(InstructionType::CastInt), "(int)" => TokenType::Instruction(InstructionType::CastInt),
"(void)" => TokenType::Instruction(InstructionType::CastVoid), "(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), "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()) t => TokenType::Unknown(t.to_string())
} }
} }

View File

@ -6,7 +6,7 @@ use std::{collections::HashMap, path::Path};
use anyhow::{bail, Result}; 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}}; 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 EXTERN = 1 << 0;
const EXPORT = 1 << 1; const EXPORT = 1 << 1;
const INLINE = 1 << 2; 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(), functions: HashMap::new(),
constants: HashMap::new(), constants: HashMap::new(),
memories: HashMap::new(), memories: HashMap::new(),
struct_defs: HashMap::new()
}; };
let syms = get_builtin_symbols(&mut prog); let syms = get_builtin_symbols(&mut prog);
@ -73,7 +74,8 @@ fn parse_next(cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, f
KeywordType::Memory => parse_memory(&token, cli_args, prog, tokens, is_module_root)?, KeywordType::Memory => parse_memory(&token, cli_args, prog, tokens, is_module_root)?,
KeywordType::Constant => parse_const(&token, cli_args, prog, tokens)?, KeywordType::Constant => parse_const(&token, cli_args, prog, tokens)?,
KeywordType::Function => parse_function(&token, cli_args, prog, tokens, flags)?, KeywordType::Function => parse_function(&token, cli_args, prog, tokens, flags)?,
KeywordType::Struct => todo!(), KeywordType::StructDef => parse_struct(&token, cli_args, prog, tokens)?,
KeywordType::TypeDef => todo!(),
KeywordType::Inline => parse_inline(&token, cli_args, prog, tokens, flags)?, KeywordType::Inline => parse_inline(&token, cli_args, prog, tokens, flags)?,
KeywordType::Export => parse_export(&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::Extern => parse_extern(&token, cli_args, prog, tokens, flags)?,
@ -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"); error!({loc => token.loc}, "Unexpected token {it:?}, please create a main function, this is not a scripting language");
bail!("") bail!("")
} else { } 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) => { 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)? 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) 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> { 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()))?; 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::Wrong(_) => (),
PeekResult::None => panic!("idk what to do herre"), 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))?; expect(tokens, TokenType::Keyword(KeywordType::End))?;
@ -152,13 +310,21 @@ fn parse_function(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &
loop { loop {
if let PeekResult::Correct(t) = peek_check_multiple(tokens, vec![ if let PeekResult::Correct(t) = peek_check_multiple(tokens, vec![
TokenType::Instruction(InstructionType::TypeAny), TokenType::Type(TypeType::Any),
TokenType::Instruction(InstructionType::TypeBool), TokenType::Type(TypeType::U8),
TokenType::Instruction(InstructionType::TypeInt), TokenType::Type(TypeType::U16),
TokenType::Instruction(InstructionType::TypePtr), TokenType::Type(TypeType::U32),
TokenType::Instruction(InstructionType::TypeVoid), 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 { } else {
break; break;
} }
@ -171,13 +337,21 @@ fn parse_function(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &
loop { loop {
if let PeekResult::Correct(t) = peek_check_multiple(tokens, vec![ if let PeekResult::Correct(t) = peek_check_multiple(tokens, vec![
TokenType::Instruction(InstructionType::TypeAny), TokenType::Type(TypeType::Any),
TokenType::Instruction(InstructionType::TypeBool), TokenType::Type(TypeType::U8),
TokenType::Instruction(InstructionType::TypeInt), TokenType::Type(TypeType::U16),
TokenType::Instruction(InstructionType::TypePtr), TokenType::Type(TypeType::U32),
TokenType::Instruction(InstructionType::TypeVoid), 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 { } else {
break; break;
} }
@ -235,7 +409,7 @@ fn parse_if(org: &Token, cli_args: &CliArgs, prog: &mut Program, tokens: &mut Ve
PeekResult::Wrong(w) => { PeekResult::Wrong(w) => {
match w.typ { match w.typ {
TokenType::Keyword(KeywordType::Then) => { 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(), functions: prog.functions.clone(),
constants: prog.constants.clone(), constants: prog.constants.clone(),
memories: prog.memories.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> { fn parse_unknown(org: &Token, _: &CliArgs, prog: &mut Program, _: &mut Vec<Token>, _: Flags ) -> Result<AstNode> {
//TODO: Typing? //TODO: Typing?
if let Some(func) = prog.functions.get(&org.lexem) { if let Some(func) = prog.functions.get(&org.lexem.clone()) {
if func.inline { if func.inline {
return Ok(AstNode::Block(Block{ loc: org.loc.clone(), body: func.body.clone(), comment: format!("inline fn {}", func.ident) })) return Ok(AstNode::Block(Block{ loc: org.loc.clone(), body: func.body.clone(), comment: format!("inline fn {}", func.ident) }))
} else { } 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() })); return Ok(AstNode::ConstUse(ConstUse{ loc: org.loc.clone(), ident: org.lexem.clone() }));
} }
if let Some(_) = prog.memories.get(&org.lexem) { if let Some(_) = prog.memories.get(&org.lexem.clone()) {
return Ok(AstNode::MemUse(MemUse{ loc: org.loc.clone(), ident: 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); error!({loc => org.loc.clone()}, "Unknown token {:?}", org);
bail!("") bail!("")
} }

View File

@ -1,17 +1,56 @@
use anyhow::bail; 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()) { match precompile_const(prog, ast, &mut Vec::new()) {
Ok(v) => { Ok(v) => {
match v { match v {
AstNode::Int(_, i) => { 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!("") 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 //TODO: Implement these

View File

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

View File

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

View File

@ -1,6 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
use super::common::Loc; use super::{ast::StructDef, common::Loc};
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum InstructionType { pub enum InstructionType {
@ -10,6 +10,8 @@ pub enum InstructionType {
PushStr(String), PushStr(String),
PushCStr(String), PushCStr(String),
PushChar(char), PushChar(char),
StructPath(Vec<String>), // foo::bar
StructItem(Vec<String>), // foo.bar
Drop, Drop,
Print, Print,
Dup, Dup,
@ -56,14 +58,6 @@ pub enum InstructionType {
CastInt, CastInt,
CastVoid, CastVoid,
// typing
TypeBool,
TypePtr,
TypeInt,
TypeVoid,
// TypeStr,
TypeAny,
FnCall, FnCall,
MemUse, MemUse,
ConstUse, ConstUse,
@ -83,7 +77,8 @@ pub enum KeywordType {
Function, Function,
Then, Then,
Done, Done,
Struct, StructDef,
TypeDef,
Inline, Inline,
Export, Export,
Extern, Extern,
@ -91,9 +86,56 @@ pub enum KeywordType {
With, 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)] #[derive(Debug, Clone, PartialEq)]
pub enum TokenType { pub enum TokenType {
Keyword(KeywordType), Keyword(KeywordType),
Type(TypeType),
Instruction(InstructionType), Instruction(InstructionType),
Unknown(String) Unknown(String)
} }

View File

@ -1,11 +1,17 @@
include "std.mcl" include "std.mcl"
// structdef Foo do structdef Uwu do
// buz do sizeof(u64) end owo do u64 end
// baz do sizeof(u64) end twt do u64 end
// done done
memory s_foo sizeof(u32) end structdef Foo do
buz do u64 end
uwu do Uwu end
done
memory s_foo Foo end
//? Comments :3 //? Comments :3
@ -15,25 +21,29 @@ memory s_foo sizeof(u32) end
// fn putd with int returns void then drop done // fn putd with int returns void then drop done
fn main with int ptr returns int then fn main with void returns void then
1 2 add
69 _dbg_print
"Hewo\n" puts
if 3 4 eq do s_foo.uwu.twt 69 write64
"omg what impossible!\n"
else if 1 1 eq do
"whaaaaaaaaa\n"
else
"finally, some good soup\n"
done
puts
10 s_foo.uwu.twt read64 _dbg_print
while dup 0 gt do // 1 2 add
"uwu " puts // 69 _dbg_print
dup _dbg_print // "Hewo\n" puts
1 sub
done // if 3 4 eq do
// "omg what impossible!\n"
// else if 1 1 eq do
// "whaaaaaaaaa\n"
// else
// "finally, some good soup\n"
// done
// puts
// 10
// while dup 0 gt do
// "uwu " puts
// dup _dbg_print
// 1 sub
// done
done done