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