something
This commit is contained in:
parent
6ae49ea4c8
commit
fe8e9da774
|
@ -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
|
|
@ -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:?}")
|
||||||
};
|
};
|
||||||
|
@ -449,12 +469,21 @@ impl Compiler for X86_64LinuxNasmCompiler {
|
||||||
for (i, s) in self.strings.iter().enumerate() {
|
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_chars = s.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, "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, "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(())
|
||||||
|
|
207
src/lexer/mod.rs
207
src/lexer/mod.rs
|
@ -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' {
|
||||||
|
@ -219,66 +301,69 @@ impl Lexer {
|
||||||
|
|
||||||
fn match_token_type(&self, s: &str) -> TokenType {
|
fn match_token_type(&self, s: &str) -> TokenType {
|
||||||
match s {
|
match s {
|
||||||
"if" => TokenType::Keyword(KeywordType::If),
|
"if" => TokenType::Keyword(KeywordType::If),
|
||||||
"else" => TokenType::Keyword(KeywordType::Else),
|
"else" => TokenType::Keyword(KeywordType::Else),
|
||||||
"end" => TokenType::Keyword(KeywordType::End),
|
"end" => TokenType::Keyword(KeywordType::End),
|
||||||
"while" => TokenType::Keyword(KeywordType::While),
|
"while" => TokenType::Keyword(KeywordType::While),
|
||||||
"do" => TokenType::Keyword(KeywordType::Do),
|
"do" => TokenType::Keyword(KeywordType::Do),
|
||||||
"include" => TokenType::Keyword(KeywordType::Include),
|
"include" => TokenType::Keyword(KeywordType::Include),
|
||||||
"memory" => TokenType::Keyword(KeywordType::Memory),
|
"memory" => TokenType::Keyword(KeywordType::Memory),
|
||||||
"const" => TokenType::Keyword(KeywordType::Constant),
|
"const" => TokenType::Keyword(KeywordType::Constant),
|
||||||
"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),
|
||||||
"inline" => TokenType::Keyword(KeywordType::Inline),
|
"structdef" => TokenType::Keyword(KeywordType::StructDef),
|
||||||
"export" => TokenType::Keyword(KeywordType::Export),
|
"inline" => TokenType::Keyword(KeywordType::Inline),
|
||||||
"extern" => TokenType::Keyword(KeywordType::Extern),
|
"export" => TokenType::Keyword(KeywordType::Export),
|
||||||
"returns" => TokenType::Keyword(KeywordType::Returns),
|
"extern" => TokenType::Keyword(KeywordType::Extern),
|
||||||
"with" => TokenType::Keyword(KeywordType::With),
|
"returns" => TokenType::Keyword(KeywordType::Returns),
|
||||||
"drop" => TokenType::Instruction(InstructionType::Drop),
|
"with" => TokenType::Keyword(KeywordType::With),
|
||||||
"_dbg_print"=> TokenType::Instruction(InstructionType::Print),
|
"drop" => TokenType::Instruction(InstructionType::Drop),
|
||||||
"dup" => TokenType::Instruction(InstructionType::Dup),
|
"_dbg_print" => TokenType::Instruction(InstructionType::Print),
|
||||||
"rot" => TokenType::Instruction(InstructionType::Rot),
|
"dup" => TokenType::Instruction(InstructionType::Dup),
|
||||||
"over" => TokenType::Instruction(InstructionType::Over),
|
"rot" => TokenType::Instruction(InstructionType::Rot),
|
||||||
"swap" => TokenType::Instruction(InstructionType::Swap),
|
"over" => TokenType::Instruction(InstructionType::Over),
|
||||||
"sub" => TokenType::Instruction(InstructionType::Minus),
|
"swap" => TokenType::Instruction(InstructionType::Swap),
|
||||||
"add" => TokenType::Instruction(InstructionType::Plus),
|
"sub" => TokenType::Instruction(InstructionType::Minus),
|
||||||
"eq" => TokenType::Instruction(InstructionType::Equals),
|
"add" => TokenType::Instruction(InstructionType::Plus),
|
||||||
"gt" => TokenType::Instruction(InstructionType::Gt),
|
"eq" => TokenType::Instruction(InstructionType::Equals),
|
||||||
"lt" => TokenType::Instruction(InstructionType::Lt),
|
"gt" => TokenType::Instruction(InstructionType::Gt),
|
||||||
"ge" => TokenType::Instruction(InstructionType::Ge),
|
"lt" => TokenType::Instruction(InstructionType::Lt),
|
||||||
"le" => TokenType::Instruction(InstructionType::Le),
|
"ge" => TokenType::Instruction(InstructionType::Ge),
|
||||||
"neq" => TokenType::Instruction(InstructionType::NotEquals),
|
"le" => TokenType::Instruction(InstructionType::Le),
|
||||||
"band" => TokenType::Instruction(InstructionType::Band),
|
"neq" => TokenType::Instruction(InstructionType::NotEquals),
|
||||||
"bor" => TokenType::Instruction(InstructionType::Bor),
|
"band" => TokenType::Instruction(InstructionType::Band),
|
||||||
"shr" => TokenType::Instruction(InstructionType::Shr),
|
"bor" => TokenType::Instruction(InstructionType::Bor),
|
||||||
"shl" => TokenType::Instruction(InstructionType::Shl),
|
"shr" => TokenType::Instruction(InstructionType::Shr),
|
||||||
"divmod" => TokenType::Instruction(InstructionType::DivMod),
|
"shl" => TokenType::Instruction(InstructionType::Shl),
|
||||||
"mul" => TokenType::Instruction(InstructionType::Mul),
|
"divmod" => TokenType::Instruction(InstructionType::DivMod),
|
||||||
"read8" => TokenType::Instruction(InstructionType::Read8),
|
"mul" => TokenType::Instruction(InstructionType::Mul),
|
||||||
"write8" => TokenType::Instruction(InstructionType::Write8),
|
"read8" => TokenType::Instruction(InstructionType::Read8),
|
||||||
"read32" => TokenType::Instruction(InstructionType::Read32),
|
"write8" => TokenType::Instruction(InstructionType::Write8),
|
||||||
"write32" => TokenType::Instruction(InstructionType::Write32),
|
"read32" => TokenType::Instruction(InstructionType::Read32),
|
||||||
"read64" => TokenType::Instruction(InstructionType::Read64),
|
"write32" => TokenType::Instruction(InstructionType::Write32),
|
||||||
"write64" => TokenType::Instruction(InstructionType::Write64),
|
"read64" => TokenType::Instruction(InstructionType::Read64),
|
||||||
"syscall0" => TokenType::Instruction(InstructionType::Syscall0),
|
"write64" => TokenType::Instruction(InstructionType::Write64),
|
||||||
"syscall1" => TokenType::Instruction(InstructionType::Syscall1),
|
"syscall0" => TokenType::Instruction(InstructionType::Syscall0),
|
||||||
"syscall2" => TokenType::Instruction(InstructionType::Syscall2),
|
"syscall1" => TokenType::Instruction(InstructionType::Syscall1),
|
||||||
"syscall3" => TokenType::Instruction(InstructionType::Syscall3),
|
"syscall2" => TokenType::Instruction(InstructionType::Syscall2),
|
||||||
"syscall4" => TokenType::Instruction(InstructionType::Syscall4),
|
"syscall3" => TokenType::Instruction(InstructionType::Syscall3),
|
||||||
"syscall5" => TokenType::Instruction(InstructionType::Syscall5),
|
"syscall4" => TokenType::Instruction(InstructionType::Syscall4),
|
||||||
"syscall6" => TokenType::Instruction(InstructionType::Syscall6),
|
"syscall5" => TokenType::Instruction(InstructionType::Syscall5),
|
||||||
"(bool)" => TokenType::Instruction(InstructionType::CastBool),
|
"syscall6" => TokenType::Instruction(InstructionType::Syscall6),
|
||||||
"(ptr)" => TokenType::Instruction(InstructionType::CastPtr),
|
"(bool)" => TokenType::Instruction(InstructionType::CastBool),
|
||||||
"(int)" => TokenType::Instruction(InstructionType::CastInt),
|
"(ptr)" => TokenType::Instruction(InstructionType::CastPtr),
|
||||||
"(void)" => TokenType::Instruction(InstructionType::CastVoid),
|
"(int)" => TokenType::Instruction(InstructionType::CastInt),
|
||||||
"bool" => TokenType::Instruction(InstructionType::TypeBool),
|
"(void)" => TokenType::Instruction(InstructionType::CastVoid),
|
||||||
"ptr" => TokenType::Instruction(InstructionType::TypePtr),
|
"return" => TokenType::Instruction(InstructionType::Return),
|
||||||
"int" => TokenType::Instruction(InstructionType::TypeInt),
|
"ptr" => TokenType::Type(TypeType::Ptr),
|
||||||
"void" => TokenType::Instruction(InstructionType::TypeVoid),
|
"u8" => TokenType::Type(TypeType::U8),
|
||||||
"any" => TokenType::Instruction(InstructionType::TypeAny),
|
"u16" => TokenType::Type(TypeType::U16),
|
||||||
"return" => TokenType::Instruction(InstructionType::Return),
|
"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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
@ -67,16 +68,17 @@ fn parse_next(cli_args: &CliArgs, prog: &mut Program, tokens: &mut Vec<Token>, f
|
||||||
let ret = match &token.typ {
|
let ret = match &token.typ {
|
||||||
TokenType::Keyword(kw) => {
|
TokenType::Keyword(kw) => {
|
||||||
match kw {
|
match kw {
|
||||||
KeywordType::If => parse_if(&token, cli_args, prog, tokens)?,
|
KeywordType::If => parse_if(&token, cli_args, prog, tokens)?,
|
||||||
KeywordType::While => parse_while(&token, cli_args, prog, tokens)?,
|
KeywordType::While => parse_while(&token, cli_args, prog, tokens)?,
|
||||||
KeywordType::Include => parse_include(&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::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::Inline => parse_inline(&token, cli_args, prog, tokens, flags)?,
|
KeywordType::TypeDef => todo!(),
|
||||||
KeywordType::Export => parse_export(&token, cli_args, prog, tokens, flags)?,
|
KeywordType::Inline => parse_inline(&token, cli_args, prog, tokens, flags)?,
|
||||||
KeywordType::Extern => parse_extern(&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 => {
|
kw => {
|
||||||
dbg!(&prog.constants);
|
dbg!(&prog.constants);
|
||||||
error!({loc => token.loc}, "Unexpected token {kw:?}");
|
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");
|
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!("")
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -55,14 +57,6 @@ pub enum InstructionType {
|
||||||
CastPtr,
|
CastPtr,
|
||||||
CastInt,
|
CastInt,
|
||||||
CastVoid,
|
CastVoid,
|
||||||
|
|
||||||
// typing
|
|
||||||
TypeBool,
|
|
||||||
TypePtr,
|
|
||||||
TypeInt,
|
|
||||||
TypeVoid,
|
|
||||||
// TypeStr,
|
|
||||||
TypeAny,
|
|
||||||
|
|
||||||
FnCall,
|
FnCall,
|
||||||
MemUse,
|
MemUse,
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
56
test.mcl
56
test.mcl
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user