functions
This commit is contained in:
parent
0a61a599c1
commit
9c84033d3f
|
@ -5,7 +5,7 @@
|
||||||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
||||||
// @arg fd: Int - file descriptor
|
// @arg fd: Int - file descriptor
|
||||||
// @ret Int
|
// @ret Int
|
||||||
macro write
|
fn write do
|
||||||
SYS_write syscall3
|
SYS_write syscall3
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ end
|
||||||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
||||||
// @arg fd: Int - file descriptor
|
// @arg fd: Int - file descriptor
|
||||||
// @ret Int
|
// @ret Int
|
||||||
macro read
|
fn read do
|
||||||
SYS_read syscall3
|
SYS_read syscall3
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ end
|
||||||
// @arg buff_size: Int - number of bytes to write
|
// @arg buff_size: Int - number of bytes to write
|
||||||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
||||||
// @ret NULL
|
// @ret NULL
|
||||||
macro puts
|
fn puts do
|
||||||
STDOUT write drop
|
STDOUT write drop
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ end
|
||||||
// @arg buff_size: Int - number of bytes to write
|
// @arg buff_size: Int - number of bytes to write
|
||||||
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
// @arg buff_ptr: Ptr - pointer to the buffer to write
|
||||||
// @ret NULL
|
// @ret NULL
|
||||||
macro eputs
|
fn eputs do
|
||||||
STDOUT write drop
|
STDOUT write drop
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ end
|
||||||
// args: [exit_code]
|
// args: [exit_code]
|
||||||
// @arg exit_code: Int
|
// @arg exit_code: Int
|
||||||
// @ret NULL/NEVER
|
// @ret NULL/NEVER
|
||||||
macro exit
|
fn exit do
|
||||||
SYS_exit syscall1 drop
|
SYS_exit syscall1 drop
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -69,11 +69,14 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
|
|
||||||
writeln!(writer, "global _start")?;
|
writeln!(writer, "global _start")?;
|
||||||
writeln!(writer, "_start:")?;
|
writeln!(writer, "_start:")?;
|
||||||
|
writeln!(writer, " call func_main")?;
|
||||||
|
writeln!(writer, " jmp end")?;
|
||||||
|
|
||||||
|
|
||||||
let mut ti = 0;
|
let mut ti = 0;
|
||||||
while ti < tokens.len() {
|
while ti < tokens.len() {
|
||||||
let token = &tokens[ti];
|
let token = &tokens[ti];
|
||||||
|
println!("{:?}", token);
|
||||||
writeln!(writer, "addr_{ti}:")?;
|
writeln!(writer, "addr_{ti}:")?;
|
||||||
match token.typ.clone() {
|
match token.typ.clone() {
|
||||||
// stack
|
// stack
|
||||||
|
@ -414,6 +417,16 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
InstructionType::CastBool => ti += 1,
|
InstructionType::CastBool => ti += 1,
|
||||||
InstructionType::CastPtr => ti += 1,
|
InstructionType::CastPtr => ti += 1,
|
||||||
InstructionType::CastInt => ti += 1,
|
InstructionType::CastInt => ti += 1,
|
||||||
|
InstructionType::FnCall => {
|
||||||
|
writeln!(writer, " ;; -- FnCall")?;
|
||||||
|
writeln!(writer, " call func_{}", token.text)?;
|
||||||
|
ti += 1;
|
||||||
|
},
|
||||||
|
InstructionType::Return => {
|
||||||
|
writeln!(writer, " ;; -- Return")?;
|
||||||
|
writeln!(writer, " ret")?;
|
||||||
|
ti += 1;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,14 +469,18 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
memories.push((token.addr.unwrap(), token.value));
|
memories.push((token.addr.unwrap(), token.value));
|
||||||
ti += 1;
|
ti += 1;
|
||||||
}
|
}
|
||||||
KeywordType::Macro |
|
KeywordType::Include => unreachable!(),
|
||||||
KeywordType::Include
|
KeywordType::Constant => todo!(),
|
||||||
=> unreachable!()
|
KeywordType::Function => {
|
||||||
|
writeln!(writer, "func_{}:", token.text)?;
|
||||||
|
ti += 1;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeln!(writer, "addr_{ti}:")?;
|
writeln!(writer, "addr_{ti}:")?;
|
||||||
|
writeln!(writer, "end:")?;
|
||||||
writeln!(writer, " mov rax, 60")?;
|
writeln!(writer, " mov rax, 60")?;
|
||||||
writeln!(writer, " mov rdi, 0")?;
|
writeln!(writer, " mov rdi, 0")?;
|
||||||
writeln!(writer, " syscall")?;
|
writeln!(writer, " syscall")?;
|
||||||
|
|
|
@ -54,6 +54,8 @@ pub enum InstructionType {
|
||||||
CastPtr,
|
CastPtr,
|
||||||
CastInt,
|
CastInt,
|
||||||
|
|
||||||
|
FnCall,
|
||||||
|
Return,
|
||||||
MemUse,
|
MemUse,
|
||||||
None // Used for macros and any other non built in word definitions
|
None // Used for macros and any other non built in word definitions
|
||||||
|
|
||||||
|
@ -65,9 +67,10 @@ pub enum KeywordType {
|
||||||
End,
|
End,
|
||||||
While,
|
While,
|
||||||
Do,
|
Do,
|
||||||
Macro,
|
|
||||||
Include,
|
Include,
|
||||||
Memory
|
Memory,
|
||||||
|
Constant,
|
||||||
|
Function
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -79,6 +82,7 @@ pub enum OpType {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Operator{
|
pub struct Operator{
|
||||||
pub typ: OpType,
|
pub typ: OpType,
|
||||||
|
pub tok_typ: TokenType,
|
||||||
pub value: usize,
|
pub value: usize,
|
||||||
pub text: String, //? only used for OpType::PushStr
|
pub text: String, //? only used for OpType::PushStr
|
||||||
pub addr: Option<usize>, //? only used for OpType::PushStr
|
pub addr: Option<usize>, //? only used for OpType::PushStr
|
||||||
|
@ -87,14 +91,15 @@ pub struct Operator{
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operator {
|
impl Operator {
|
||||||
pub fn new(typ: OpType, value: usize, text: String, file: String, row: usize, col: usize) -> Self {
|
pub fn new(typ: OpType, tok_typ: TokenType, value: usize, text: String, file: String, row: usize, col: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
typ,
|
typ,
|
||||||
value,
|
value,
|
||||||
jmp: 0,
|
jmp: 0,
|
||||||
addr: None,
|
addr: None,
|
||||||
text,
|
text,
|
||||||
loc: (file, row, col)
|
loc: (file, row, col),
|
||||||
|
tok_typ,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn set_addr(mut self, addr: usize) -> Self {
|
pub fn set_addr(mut self, addr: usize) -> Self {
|
||||||
|
@ -151,6 +156,8 @@ impl OpType {
|
||||||
InstructionType::CastInt => "cast(int)",
|
InstructionType::CastInt => "cast(int)",
|
||||||
InstructionType::MemUse => "MemUse",
|
InstructionType::MemUse => "MemUse",
|
||||||
InstructionType::None => "None",
|
InstructionType::None => "None",
|
||||||
|
InstructionType::FnCall => "Function Call",
|
||||||
|
InstructionType::Return => "return",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OpType::Keyword(keyword) => {
|
OpType::Keyword(keyword) => {
|
||||||
|
@ -160,9 +167,10 @@ impl OpType {
|
||||||
KeywordType::End => "end",
|
KeywordType::End => "end",
|
||||||
KeywordType::While => "while",
|
KeywordType::While => "while",
|
||||||
KeywordType::Do => "do",
|
KeywordType::Do => "do",
|
||||||
KeywordType::Macro => "macro",
|
|
||||||
KeywordType::Include => "include",
|
KeywordType::Include => "include",
|
||||||
KeywordType::Memory => "memory"
|
KeywordType::Memory => "memory",
|
||||||
|
KeywordType::Function => "fn",
|
||||||
|
KeywordType::Constant => "const",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,7 +187,7 @@ pub struct Token {
|
||||||
pub typ: TokenType,
|
pub typ: TokenType,
|
||||||
pub value: Option<usize>, //* only used for Memories
|
pub value: Option<usize>, //* only used for Memories
|
||||||
pub addr: Option<usize>, //* only used for Memories
|
pub addr: Option<usize>, //* only used for Memories
|
||||||
pub op_typ: InstructionType //* only used for Memories
|
pub op_typ: OpType //* only used for Memories
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||||
|
|
|
@ -298,6 +298,8 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
|
||||||
InstructionType::CastPtr => ti += 1,
|
InstructionType::CastPtr => ti += 1,
|
||||||
InstructionType::CastInt => ti += 1,
|
InstructionType::CastInt => ti += 1,
|
||||||
InstructionType::None => unreachable!(),
|
InstructionType::None => unreachable!(),
|
||||||
|
InstructionType::FnCall => todo!(),
|
||||||
|
InstructionType::Return => todo!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -331,7 +333,9 @@ pub fn run(tokens: &[crate::constants::Operator]) -> Result<i32>{
|
||||||
memories.insert(token.addr.unwrap(), token.value);
|
memories.insert(token.addr.unwrap(), token.value);
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
KeywordType::Macro | KeywordType::Include => unreachable!(),
|
KeywordType::Include => unreachable!(),
|
||||||
|
KeywordType::Constant => todo!(),
|
||||||
|
KeywordType::Function => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ fn lex_line(text: &str) -> Vec<(usize, String, TokenType)> {
|
||||||
tokens
|
tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, args: &Args, preprocessing: bool) -> Result<Vec<Token>> {
|
pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, args: &Args) -> Result<Vec<Token>> {
|
||||||
let lines: Vec<(usize, &str)> = code
|
let lines: Vec<(usize, &str)> = code
|
||||||
.split(['\n', '\r'])
|
.split(['\n', '\r'])
|
||||||
.enumerate()
|
.enumerate()
|
||||||
|
@ -111,7 +111,7 @@ pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, args: &Args
|
||||||
typ: tok_type,
|
typ: tok_type,
|
||||||
value: None,
|
value: None,
|
||||||
addr: None,
|
addr: None,
|
||||||
op_typ: crate::constants::InstructionType::None
|
op_typ: crate::constants::OpType::Instruction(crate::constants::InstructionType::None)
|
||||||
};
|
};
|
||||||
tokens.push(t);
|
tokens.push(t);
|
||||||
}
|
}
|
||||||
|
@ -121,9 +121,7 @@ pub fn lex<S: Into<String> + std::marker::Copy>(code: &str, file: S, args: &Args
|
||||||
// for token in tokens.clone() {
|
// for token in tokens.clone() {
|
||||||
// println!("tok: {:?}", token.text);
|
// println!("tok: {:?}", token.text);
|
||||||
// }
|
// }
|
||||||
if preprocessing {
|
|
||||||
(tokens, _) = preprocess(tokens, args)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(tokens)
|
Ok(tokens)
|
||||||
}
|
}
|
|
@ -70,14 +70,14 @@ fn main() {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
};
|
};
|
||||||
let Ok(tokens) = lexer::lex(&code, &args.in_file, &args, true) else {
|
let Ok(tokens) = lexer::lex(&code, &args.in_file, &args) else {
|
||||||
error!("Lexing failed, exiting!");
|
error!("Lexing failed, exiting!");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let mut parser = parser::Parser::new(tokens);
|
let mut parser = parser::Parser::new(tokens);
|
||||||
let Ok(tokens) = parser.parse() else {
|
let Ok(tokens) = parser.parse(&args) else {
|
||||||
error!("Parsing failed, exiting!");
|
error!("Parsing failed, exiting!");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType}, lerror};
|
use crate::{constants::{Operator, OpType, Token, TokenType, Loc, KeywordType, InstructionType}, lerror, preprocessor::preprocess, Args};
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use eyre::eyre;
|
use eyre::eyre;
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
|
||||||
let op = &program.clone()[ip];
|
let op = &program.clone()[ip];
|
||||||
match op.typ {
|
match op.typ {
|
||||||
OpType::Keyword(KeywordType::If) |
|
OpType::Keyword(KeywordType::If) |
|
||||||
|
OpType::Keyword(KeywordType::Function) |
|
||||||
OpType::Keyword(KeywordType::While) => {
|
OpType::Keyword(KeywordType::While) => {
|
||||||
stack.push(ip);
|
stack.push(ip);
|
||||||
}
|
}
|
||||||
|
@ -36,6 +37,9 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
|
||||||
} else if program[block_ip].typ == OpType::Keyword(KeywordType::Do) {
|
} else if program[block_ip].typ == OpType::Keyword(KeywordType::Do) {
|
||||||
program[ip].jmp = program[block_ip].jmp;
|
program[ip].jmp = program[block_ip].jmp;
|
||||||
program[block_ip].jmp = ip + 1;
|
program[block_ip].jmp = ip + 1;
|
||||||
|
} else if program[block_ip].typ == OpType::Keyword(KeywordType::Function) {
|
||||||
|
program[ip].typ = OpType::Instruction(InstructionType::Return);
|
||||||
|
program[block_ip].typ = OpType::Keyword(KeywordType::Do);
|
||||||
} else {
|
} else {
|
||||||
lerror!(&op.clone().loc,"'end' can only close 'if' blocks");
|
lerror!(&op.clone().loc,"'end' can only close 'if' blocks");
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
|
@ -43,8 +47,14 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
|
||||||
|
|
||||||
}
|
}
|
||||||
OpType::Keyword(KeywordType::Do) => {
|
OpType::Keyword(KeywordType::Do) => {
|
||||||
let while_ip = stack.pop().unwrap();
|
let block_ip = stack.pop().unwrap();
|
||||||
program[ip].jmp = while_ip;
|
|
||||||
|
if program[block_ip].typ == OpType::Keyword(KeywordType::Function) {
|
||||||
|
program[ip].typ = OpType::Keyword(KeywordType::Function);
|
||||||
|
}
|
||||||
|
|
||||||
|
program[ip].jmp = block_ip;
|
||||||
|
// println!("{}", block_ip);
|
||||||
stack.push(ip);
|
stack.push(ip);
|
||||||
}
|
}
|
||||||
_ => ()
|
_ => ()
|
||||||
|
@ -71,7 +81,7 @@ impl Parser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&mut self) -> Result<Vec<Operator>> {
|
pub fn parse(&mut self, args: &Args) -> Result<Vec<Operator>> {
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
|
|
||||||
for token in &self.tokens {
|
for token in &self.tokens {
|
||||||
|
@ -81,19 +91,19 @@ impl Parser {
|
||||||
let pos = (token.file.clone(), token.line, token.col);
|
let pos = (token.file.clone(), token.line, token.col);
|
||||||
match token.typ {
|
match token.typ {
|
||||||
TokenType::Word => {
|
TokenType::Word => {
|
||||||
let word_type = if token.op_typ == InstructionType::MemUse {
|
let word_type = if token.op_typ == OpType::Instruction(InstructionType::MemUse) {
|
||||||
OpType::Instruction(InstructionType::MemUse)
|
OpType::Instruction(InstructionType::MemUse)
|
||||||
} else {
|
} else {
|
||||||
lookup_word(&token.text, &pos)
|
lookup_word(&token.text, &pos)
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.push(Operator::new(word_type, token.value.unwrap_or(0), token.text.clone(), token.file.clone(), token.line, token.col).set_addr(token.addr.unwrap_or(0)));
|
tokens.push(Operator::new(word_type, token.typ, token.value.unwrap_or(0), token.text.clone(), token.file.clone(), token.line, token.col).set_addr(token.addr.unwrap_or(0)));
|
||||||
},
|
},
|
||||||
TokenType::Int => {// negative numbers not yet implemented
|
TokenType::Int => {// negative numbers not yet implemented
|
||||||
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.text.parse::<usize>()?, String::new(), token.file.clone(), token.line, token.col));
|
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.typ, token.text.parse::<usize>()?, String::new(), token.file.clone(), token.line, token.col));
|
||||||
},
|
},
|
||||||
TokenType::String => {
|
TokenType::String => {
|
||||||
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushStr), 0, token.text.clone(), token.file.clone(), token.line, token.col));
|
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushStr), token.typ, 0, token.text.clone(), token.file.clone(), token.line, token.col));
|
||||||
}
|
}
|
||||||
TokenType::Char => {
|
TokenType::Char => {
|
||||||
let c = token.text.clone();
|
let c = token.text.clone();
|
||||||
|
@ -102,7 +112,7 @@ impl Parser {
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.text.chars().next().unwrap() as usize, String::new(), token.file.clone(), token.line, token.col));
|
tokens.push(Operator::new(OpType::Instruction(InstructionType::PushInt), token.typ, token.text.chars().next().unwrap() as usize, String::new(), token.file.clone(), token.line, token.col));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -110,7 +120,10 @@ impl Parser {
|
||||||
//"print" => tokens.push(Operator::new(OpType::Print, 0, token.file.clone(), token.line, token.col)),
|
//"print" => tokens.push(Operator::new(OpType::Print, 0, token.file.clone(), token.line, token.col)),
|
||||||
}
|
}
|
||||||
|
|
||||||
cross_ref(tokens)
|
|
||||||
|
tokens = cross_ref(tokens.clone())?;
|
||||||
|
let t = preprocess(tokens, args)?;
|
||||||
|
Ok(t.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,9 +185,10 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
|
||||||
"end" => OpType::Keyword(KeywordType::End),
|
"end" => OpType::Keyword(KeywordType::End),
|
||||||
"while" => OpType::Keyword(KeywordType::While),
|
"while" => OpType::Keyword(KeywordType::While),
|
||||||
"do" => OpType::Keyword(KeywordType::Do),
|
"do" => OpType::Keyword(KeywordType::Do),
|
||||||
"macro" => OpType::Keyword(KeywordType::Macro),
|
|
||||||
"include" => OpType::Keyword(KeywordType::Include),
|
"include" => OpType::Keyword(KeywordType::Include),
|
||||||
"memory" => OpType::Keyword(KeywordType::Memory),
|
"memory" => OpType::Keyword(KeywordType::Memory),
|
||||||
|
"const" => OpType::Keyword(KeywordType::Constant),
|
||||||
|
"fn" => OpType::Keyword(KeywordType::Function),
|
||||||
_ => OpType::Instruction(InstructionType::None)
|
_ => OpType::Instruction(InstructionType::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use eyre::eyre;
|
use eyre::eyre;
|
||||||
|
|
||||||
use crate::{constants::{Token, OpType, InstructionType, Loc}, parser::lookup_word, lerror};
|
use crate::{constants::{Token, OpType, InstructionType, Loc, Operator}, parser::lookup_word, lerror};
|
||||||
|
|
||||||
fn stack_pop(stack: &mut Vec<usize>, loc: &Loc) -> Result<usize> {
|
fn stack_pop(stack: &mut Vec<usize>, loc: &Loc) -> Result<usize> {
|
||||||
if let Some(i) = stack.pop() { Ok(i) } else {
|
if let Some(i) = stack.pop() { Ok(i) } else {
|
||||||
|
@ -11,21 +11,20 @@ fn stack_pop(stack: &mut Vec<usize>, loc: &Loc) -> Result<usize> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn precompile(tokens: &Vec<Token>) -> Result<Vec<usize>>{
|
pub fn precompile(tokens: &Vec<Operator>) -> Result<Vec<usize>>{
|
||||||
|
|
||||||
let mut stack: Vec<usize> = Vec::new();
|
let mut stack: Vec<usize> = Vec::new();
|
||||||
|
|
||||||
for token in tokens.iter() {
|
for token in tokens.iter() {
|
||||||
let typ = lookup_word(&token.text, &token.loc());
|
match token.typ.clone() {
|
||||||
match typ {
|
|
||||||
OpType::Instruction(i) => {
|
OpType::Instruction(i) => {
|
||||||
let loc = token.loc();
|
let loc = token.loc.clone();
|
||||||
match i {
|
match i {
|
||||||
InstructionType::PushInt => {
|
InstructionType::PushInt => {
|
||||||
if let Ok(i) = token.text.parse::<usize>() {
|
if let Ok(i) = token.text.parse::<usize>() {
|
||||||
stack.push(i);
|
stack.push(i);
|
||||||
} else {
|
} else {
|
||||||
lerror!(&token.loc(), "Bad number");
|
lerror!(&token.loc, "Bad number");
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -136,14 +135,14 @@ pub fn precompile(tokens: &Vec<Token>) -> Result<Vec<usize>>{
|
||||||
stack.push(b);
|
stack.push(b);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
lerror!(&token.loc(), "Unsupported precompiler instruction {:?}", i);
|
lerror!(&token.loc, "Unsupported precompiler instruction {:?}", i);
|
||||||
dbg!(tokens);
|
dbg!(tokens);
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
lerror!(&token.loc(), "Unsupported precompiler keyword {:?}", typ);
|
lerror!(&token.loc, "Unsupported precompiler keyword {:?}", token.typ);
|
||||||
dbg!(tokens);
|
dbg!(tokens);
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,26 +4,26 @@ use std::path::{PathBuf, Path};
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use eyre::eyre;
|
use eyre::eyre;
|
||||||
|
|
||||||
use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType};
|
use crate::constants::{Token, Loc, OpType, TokenType, KeywordType, InstructionType, Operator};
|
||||||
use crate::lexer::lex;
|
use crate::lexer::lex;
|
||||||
use crate::precompiler::precompile;
|
use crate::precompiler::precompile;
|
||||||
use crate::{lerror, lnote, Args, warn, linfo};
|
use crate::{lerror, lnote, Args, warn, linfo, parser};
|
||||||
use crate::parser::lookup_word;
|
use crate::parser::lookup_word;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Macro {
|
pub struct Function {
|
||||||
pub loc: Loc,
|
pub loc: Loc,
|
||||||
pub tokens: Vec<Token>
|
pub name: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type Macros = HashMap<String, Macro>;
|
type Functions = HashMap<String, Function>;
|
||||||
type Memories = HashMap<String, usize>;
|
type Memories = HashMap<String, usize>;
|
||||||
|
|
||||||
pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<(Vec<Token>, Macros)>{
|
pub fn preprocess(tokens: Vec<Operator>, args: &Args) -> Result<(Vec<Operator>, Functions)>{
|
||||||
|
|
||||||
|
|
||||||
let mut program: Vec<Token> = Vec::new();
|
let mut program: Vec<Operator> = Vec::new();
|
||||||
let mut macros: Macros = HashMap::new();
|
let mut functions: Functions = HashMap::new();
|
||||||
let mut memories: Memories = HashMap::new();
|
let mut memories: Memories = HashMap::new();
|
||||||
|
|
||||||
let mut rtokens = tokens;
|
let mut rtokens = tokens;
|
||||||
|
@ -31,74 +31,20 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<(Vec<Token>, Macros
|
||||||
while !rtokens.is_empty() {
|
while !rtokens.is_empty() {
|
||||||
let mut token = rtokens.pop().unwrap();
|
let mut token = rtokens.pop().unwrap();
|
||||||
|
|
||||||
let op_type = lookup_word(&token.text, &token.loc());
|
let op_type = token.typ.clone();
|
||||||
match token.clone() {
|
match token.clone() {
|
||||||
_ if op_type == OpType::Keyword(KeywordType::Macro) => {
|
|
||||||
if rtokens.is_empty(){
|
|
||||||
lerror!(&token.loc(), "Macro name not found, expected {} but found nothing", TokenType::Word.human());
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
let macro_name = rtokens.pop().unwrap();
|
|
||||||
|
|
||||||
if macro_name.typ != TokenType::Word {
|
|
||||||
lerror!(¯o_name.loc(), "Bad macro name, expected {} but found {}", TokenType::Word.human(), macro_name.typ.human());
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
let word = lookup_word(¯o_name.text, ¯o_name.loc());
|
|
||||||
if word != OpType::Instruction(InstructionType::None) {
|
|
||||||
lerror!(¯o_name.loc(), "Macro name cannot be a built in word, got '{}'", word.human());
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
if macros.get(¯o_name.text.clone()).is_some() && crate::constants::ALLOW_MACRO_REDEFINITION {
|
|
||||||
lerror!(¯o_name.loc(), "Macro redefinition is not allowed");
|
|
||||||
lnote!(¯os.get(¯o_name.text).unwrap().loc, "First definition here");
|
|
||||||
return Err(eyre!(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut macr = Macro{ loc: macro_name.loc(), tokens: Vec::new() };
|
|
||||||
let mut reprocess = false;
|
|
||||||
let mut depth = 0;
|
|
||||||
while !rtokens.is_empty() {
|
|
||||||
let t = rtokens.pop().unwrap();
|
|
||||||
let typ = lookup_word(&t.text, &t.loc());
|
|
||||||
if typ == OpType::Keyword(KeywordType::End) && depth == 0 {
|
|
||||||
break;
|
|
||||||
} else if typ == OpType::Keyword(KeywordType::End) && depth != 0 {
|
|
||||||
depth -= 1;
|
|
||||||
macr.tokens.push(t);
|
|
||||||
} else if typ == OpType::Keyword(KeywordType::If) ||
|
|
||||||
typ == OpType::Keyword(KeywordType::Do) {
|
|
||||||
macr.tokens.push(t);
|
|
||||||
depth += 1;
|
|
||||||
} else if typ == OpType::Keyword(KeywordType::Macro) {
|
|
||||||
reprocess = true;
|
|
||||||
macr.tokens.push(t);
|
|
||||||
depth += 1;
|
|
||||||
} else {
|
|
||||||
macr.tokens.push(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if reprocess {
|
|
||||||
(macr.tokens, macros) = preprocess(macr.tokens, args)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
macros.insert(macro_name.text, macr);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
_ if op_type == OpType::Keyword(KeywordType::Include) => {
|
_ if op_type == OpType::Keyword(KeywordType::Include) => {
|
||||||
if rtokens.is_empty() {
|
if rtokens.is_empty() {
|
||||||
lerror!(&token.loc(), "Include path not found, expected {} but found nothing", TokenType::String.human());
|
lerror!(&token.loc, "Include path not found, expected {} but found nothing", TokenType::String.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
let include_path = rtokens.pop().unwrap();
|
let include_path = rtokens.pop().unwrap();
|
||||||
|
|
||||||
if include_path.typ != TokenType::String {
|
if include_path.tok_typ != TokenType::String {
|
||||||
lerror!(&include_path.loc(), "Bad include path, expected {} but found {}", TokenType::String.human(), include_path.typ.human());
|
lerror!(&include_path.loc, "Bad include path, expected {} but found {}", TokenType::String.human(), include_path.typ.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +54,7 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<(Vec<Token>, Macros
|
||||||
let mut include_code = String::new();
|
let mut include_code = String::new();
|
||||||
|
|
||||||
if include_path.text.chars().collect::<Vec<char>>()[0] == '.' {
|
if include_path.text.chars().collect::<Vec<char>>()[0] == '.' {
|
||||||
let p = Path::new(include_path.file.as_str());
|
let p = Path::new(include_path.loc.0.as_str());
|
||||||
let p = p.parent().unwrap();
|
let p = p.parent().unwrap();
|
||||||
let p = p.join(&include_path.text);
|
let p = p.join(&include_path.text);
|
||||||
include_code = std::fs::read_to_string(p)?;
|
include_code = std::fs::read_to_string(p)?;
|
||||||
|
@ -125,11 +71,12 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<(Vec<Token>, Macros
|
||||||
}
|
}
|
||||||
|
|
||||||
if include_code.is_empty() {
|
if include_code.is_empty() {
|
||||||
lerror!(&include_path.loc(), "Include file in path '{}' was not found or is empty", include_path.text);
|
lerror!(&include_path.loc, "Include file in path '{}' was not found or is empty", include_path.text);
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
let code = lex(&include_code, &args.in_file, &args)?;
|
||||||
let mut code = lex(&include_code, &include_path.text, args, false)?;
|
let mut p = parser::Parser::new(code);
|
||||||
|
let mut code = p.parse(args)?;
|
||||||
code.reverse();
|
code.reverse();
|
||||||
rtokens.append(&mut code);
|
rtokens.append(&mut code);
|
||||||
|
|
||||||
|
@ -137,30 +84,30 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<(Vec<Token>, Macros
|
||||||
}
|
}
|
||||||
_ if op_type == OpType::Keyword(KeywordType::Memory) => {
|
_ if op_type == OpType::Keyword(KeywordType::Memory) => {
|
||||||
if rtokens.is_empty() {
|
if rtokens.is_empty() {
|
||||||
lerror!(&token.loc(), "Memory name not found, expected {} but found nothing", TokenType::String.human());
|
lerror!(&token.loc, "Memory name not found, expected {} but found nothing", TokenType::String.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
let memory_name = rtokens.pop().unwrap();
|
let memory_name = rtokens.pop().unwrap();
|
||||||
|
|
||||||
if memory_name.typ != TokenType::Word {
|
if memory_name.tok_typ != TokenType::Word {
|
||||||
lerror!(&memory_name.loc(), "Bad memory name, expected {} but found {}", TokenType::Word.human(), memory_name.typ.human());
|
lerror!(&memory_name.loc, "Bad memory name, expected {} but found {}", TokenType::Word.human(), memory_name.typ.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
if macros.get(&memory_name.text).is_some() {
|
if functions.get(&memory_name.text).is_some() {
|
||||||
lerror!(&memory_name.loc(), "Memory name cannot replace macro name, got {}", memory_name.text);
|
lerror!(&memory_name.loc, "Memory name cannot replace function name, got {}", memory_name.text);
|
||||||
let m = macros.get(&memory_name.text).unwrap();
|
let m = functions.get(&memory_name.text).unwrap();
|
||||||
linfo!(&m.loc, "Macro found here");
|
linfo!(&m.loc, "Function found here");
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut code: Vec<Token> = Vec::new();
|
let mut code: Vec<Operator> = Vec::new();
|
||||||
|
|
||||||
let mut depth = 0;
|
let mut depth = 0;
|
||||||
while !rtokens.is_empty() {
|
while !rtokens.is_empty() {
|
||||||
let t = rtokens.pop().unwrap();
|
let t = rtokens.pop().unwrap();
|
||||||
let typ = lookup_word(&t.text, &t.loc());
|
let typ = t.typ.clone();
|
||||||
if typ == OpType::Keyword(KeywordType::End) && depth == 0 {
|
if typ == OpType::Keyword(KeywordType::End) && depth == 0 {
|
||||||
break;
|
break;
|
||||||
} else if typ == OpType::Keyword(KeywordType::End) && depth != 0 {
|
} else if typ == OpType::Keyword(KeywordType::End) && depth != 0 {
|
||||||
|
@ -176,17 +123,52 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<(Vec<Token>, Macros
|
||||||
let res = precompile(&code)?;
|
let res = precompile(&code)?;
|
||||||
|
|
||||||
if res.len() != 1 {
|
if res.len() != 1 {
|
||||||
lerror!(&token.loc(), "Expected 1 number, got {:?}", res);
|
lerror!(&token.loc, "Expected 1 number, got {:?}", res);
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
token.value = Some(res[0]);
|
token.value = res[0];
|
||||||
token.addr = Some(memories.len());
|
token.addr = Some(memories.len());
|
||||||
program.push(token);
|
program.push(token);
|
||||||
|
|
||||||
memories.insert(memory_name.text, memories.len());
|
memories.insert(memory_name.text, memories.len());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
_ if op_type == OpType::Keyword(KeywordType::Function) => {
|
||||||
|
if rtokens.is_empty() {
|
||||||
|
lerror!(&token.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human());
|
||||||
|
return Err(eyre!(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
let function_name = rtokens.pop().unwrap();
|
||||||
|
|
||||||
|
if function_name.tok_typ != TokenType::Word {
|
||||||
|
lerror!(&function_name.loc, "Bad Function name, expected {} but found {}", TokenType::Word.human(), function_name.typ.human());
|
||||||
|
return Err(eyre!(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
if memories.get(&function_name.text).is_some() {
|
||||||
|
lerror!(&function_name.loc, "Function name cannot replace memory name, got {}", function_name.text);
|
||||||
|
return Err(eyre!(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
if functions.get(&function_name.text).is_some() {
|
||||||
|
lerror!(&function_name.loc, "Functions cannot be redefined, got {}", function_name.text);
|
||||||
|
return Err(eyre!(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
functions.insert(function_name.text.clone(), Function{
|
||||||
|
loc: function_name.loc.clone(),
|
||||||
|
name: function_name.text.clone(),
|
||||||
|
});
|
||||||
|
token.text = function_name.text;
|
||||||
|
rtokens.pop();
|
||||||
|
program.push(token);
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
if op_type == OpType::Keyword(KeywordType::Do) {
|
||||||
|
println!("{:?}", token);
|
||||||
|
}
|
||||||
program.push(token);
|
program.push(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,8 +178,8 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<(Vec<Token>, Macros
|
||||||
//* i wanna kms
|
//* i wanna kms
|
||||||
let mut times = 0;
|
let mut times = 0;
|
||||||
while program.iter().map(|f| {
|
while program.iter().map(|f| {
|
||||||
if f.typ == TokenType::Word && f.op_typ != InstructionType::MemUse {
|
if f.tok_typ == TokenType::Word && f.typ != OpType::Instruction(InstructionType::FnCall) && f.typ != OpType::Instruction(InstructionType::MemUse){
|
||||||
lookup_word(&f.text, &f.loc())
|
lookup_word(&f.text, &f.loc)
|
||||||
} else {
|
} else {
|
||||||
OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works
|
OpType::Instruction(InstructionType::PushInt) // i hate myself, this is a randomly picked optype so its happy and works
|
||||||
}
|
}
|
||||||
|
@ -208,60 +190,56 @@ pub fn preprocess(tokens: Vec<Token>, args: &Args) -> Result<(Vec<Token>, Macros
|
||||||
warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it");
|
warn!("File import depth maxed out, if the program crashes try reducing the import depth, good luck youll need it");
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
program = expand(program, ¯os, &memories)?;
|
program = expand(program, &functions, &memories)?;
|
||||||
times += 1;
|
times += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Ok((program, macros))
|
Ok((program, functions))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expand(tokens: Vec<Token>, macros: &Macros, mems: &Memories) -> Result<Vec<Token>> {
|
pub fn expand(tokens: Vec<Operator>, funcs: &Functions, mems: &Memories) -> Result<Vec<Operator>> {
|
||||||
let mut program: Vec<Token> = Vec::new();
|
let mut program: Vec<Operator> = Vec::new();
|
||||||
|
|
||||||
let mut rtokens = tokens.clone();
|
let mut rtokens = tokens.clone();
|
||||||
rtokens.reverse();
|
rtokens.reverse();
|
||||||
|
|
||||||
while !rtokens.is_empty() {
|
while !rtokens.is_empty() {
|
||||||
let op = rtokens.pop().unwrap();
|
let op = rtokens.pop().unwrap();
|
||||||
let op_type = lookup_word(&op.text, &op.loc());
|
let op_type = op.typ.clone();
|
||||||
if op.typ == TokenType::Word {
|
if op.tok_typ.clone() == TokenType::Word {
|
||||||
match op_type {
|
match op_type {
|
||||||
OpType::Instruction(InstructionType::None) => {
|
OpType::Instruction(InstructionType::None) => {
|
||||||
let m = macros.get(&op.text);
|
let m = funcs.get(&op.text);
|
||||||
let mem = mems.get(&op.text);
|
let mem = mems.get(&op.text);
|
||||||
if let Some(m) = m {
|
if let Some(m) = m {
|
||||||
// println!("{:#?}", macros);
|
let mut t = op.clone();
|
||||||
let mut toks = m.tokens.clone();
|
t.typ = OpType::Instruction(InstructionType::FnCall);
|
||||||
// if toks.iter().map(|t| {
|
t.text = m.name.clone();
|
||||||
// let w = lookup_word(&t.text, &t.loc());
|
program.push(t);
|
||||||
// w == OpType::Keyword(KeywordType::Macro)
|
|
||||||
// }).collect::<Vec<bool>>().contains(&true) {
|
|
||||||
// println!("yas");
|
|
||||||
// toks = preprocess(toks, args)?;
|
|
||||||
// }
|
|
||||||
program.append(&mut toks);
|
|
||||||
// println!("{:?}", program);
|
|
||||||
} else
|
} else
|
||||||
if let Some(mem) = mem {
|
if let Some(mem) = mem {
|
||||||
let mut t = op;
|
let mut t = op.clone();
|
||||||
t.addr = Some(*mem);
|
t.addr = Some(*mem);
|
||||||
t.op_typ = InstructionType::MemUse;
|
t.typ = OpType::Instruction(InstructionType::MemUse);
|
||||||
program.push(t);
|
program.push(t);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
lerror!(&op.loc(), "Unknown word '{}'", op.text.clone());
|
lerror!(&op.loc, "expand: Unknown word '{}'", op.text.clone());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
program.push(op);
|
program.push(op.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
program.push(op);
|
program.push(op.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if op.typ == OpType::Keyword(KeywordType::Do) {
|
||||||
|
println!("expand: {:?}", op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,9 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
|
||||||
KeywordType::Else |
|
KeywordType::Else |
|
||||||
KeywordType::End |
|
KeywordType::End |
|
||||||
KeywordType::While |
|
KeywordType::While |
|
||||||
KeywordType::Macro |
|
KeywordType::Function |
|
||||||
KeywordType::Include |
|
KeywordType::Include |
|
||||||
|
KeywordType::Constant |
|
||||||
KeywordType::Memory => (),
|
KeywordType::Memory => (),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -235,6 +236,8 @@ pub fn typecheck(ops: &[Operator], args: &Args) -> Result<Vec<Operator>>{
|
||||||
InstructionType::MemUse => {
|
InstructionType::MemUse => {
|
||||||
stack.push(Types::Ptr);
|
stack.push(Types::Ptr);
|
||||||
},
|
},
|
||||||
|
InstructionType::FnCall |
|
||||||
|
InstructionType::Return |
|
||||||
InstructionType::None => {},
|
InstructionType::None => {},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue
Block a user