diff --git a/Cargo.toml b/Cargo.toml index a40e8ca..3bca400 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,9 @@ name = "skylang" version = "0.1.0" edition = "2021" +[lib] +proc-macro = true + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/justfile b/justfile new file mode 100644 index 0000000..3bdde5c --- /dev/null +++ b/justfile @@ -0,0 +1,6 @@ +run: + cargo run -r +test: + cargo test +build: + cargo build -r diff --git a/src/#main.rs# b/src/#main.rs# new file mode 100644 index 0000000..5605800 --- /dev/null +++ b/src/#main.rs# @@ -0,0 +1,66 @@ +#![allow(warnings)] + +pub mod lex; +pub mod codegen; +use crate::codegen::fasm::*; +use crate::lex::tok::*; +use crate::parse::ast::*; +use crate::parse::parse::*; +use logos::Logos; + +pub mod parse; + +macro_rules! arrow { + ($spaces:expr) => { + println!("{}↓", $spaces); + } +} + +fn main() { + // let fc = fasm_codegen!( + // vec![ + // Expr::VarDefinition(VarDefinition {name: "goren", value: Value::Number(10)}), + // Expr::MathExpr(Math { + // left: &Value::Var(VarReference { name: "goren"}), + // right: &Value::Number(17), + // operator: MathOperator::OP_MULT + // } + // ), + // Expr::FunDefinition(FunDefinition { + // name: "adder", contents: vec![ + // Expr::MathExpr( + // Math { + // left: &Value::Param(ParamReference {param_number: 0}), + // right: &Value::Param(ParamReference {param_number: 1}), + // operator: MathOperator::OP_ADD + // } + // ) + // ] + // }), + + // Expr::FunCall( + // FunCall { + // name: "adder", + // params: vec![Value::Var(VarReference {name: "goren"}), Value::Number(6)] + // } + // ), + + // Expr::Breakpoint + // ] + // ); + + + // println!("{}", fc); + let parsed = "30 * 60"; + + let mut lexer = Token::lexer(parsed); + + println!("\"{}\"", parsed); + arrow!(" "); + println!("{:?}", lex_str(parsed)); + arrow!(" "); + let parsed = parse_math(lexer); + println!("{:?}", parsed); + arrow!(" "); + println!("{}", fasm_codegen!(&vec![parsed.unwrap()])); +} diff --git a/src/codegen/fasm.rs b/src/codegen/fasm.rs index d840aca..31854e8 100644 --- a/src/codegen/fasm.rs +++ b/src/codegen/fasm.rs @@ -1,10 +1,12 @@ use crate::parse::ast::*; +use std::rc::Rc; +use skylang::temp; #[macro_export] macro_rules! fasm_codegen { // Macro to make calling fasm_codegen function easier. ($exprs:expr) => { - fasm_codegen(&$exprs, true) + fasm_codegen($exprs, true) }; (fun: $exprs:expr) => { @@ -12,20 +14,19 @@ macro_rules! fasm_codegen { } } -pub fn temp(counter: u64) -> String { - format!("tmp{:?}", counter) -} - pub fn fasm_codegen(exprs: &Vec, not_a_function: bool) -> String { - // A counter for how many temporary variables have been created. This is used to create new ones. The new ones will be called tmp1, tmp2, etc. - let mut tmp_counter: u64 = 0; - // Define asm_func, used for functions. let mut asm_func = String::new(); // Define asm_data, used for variables. let mut asm_data = String::new(); // Define asm_start, used for the entry point. let mut asm_start = String::new(); + macro_rules! unwrap { + ($item:expr) => { + asm_start.push_str(fasm_codegen!(fun: &vec![$item.as_ref().clone()]).as_str()); + } + } + // If not_a_function, push necessary headers to the asm_start variable. if not_a_function { @@ -35,15 +36,17 @@ pub fn fasm_codegen(exprs: &Vec, not_a_function: bool) -> String { asm_start.push_str("_start:\n"); asm_data.push_str("\nsegment readable writable\n"); } - + // Iterate over expressions. for expr in exprs.iter() { // Use patern matching on `expr`. match expr { // If the expression is a math expression. Expr::MathExpr(e) => { - asm_start.push_str(format!("\tmov r10, {}\n", e.left.unwrap()).as_str()); - asm_start.push_str(format!("\tmov r11, {}\n", e.right.unwrap()).as_str()); + unwrap!(e.left); + asm_start.push_str(format!("\tmov r10, rax\n").as_str()); + unwrap!(e.right); + asm_start.push_str(format!("\tmov r11, rax\n").as_str()); match e.operator { // If the operator is addition. MathOperator::OP_ADD => { @@ -91,43 +94,51 @@ pub fn fasm_codegen(exprs: &Vec, not_a_function: bool) -> String { for (i, p) in e.params.iter().enumerate() { match i { 0 => { - // First parameter. Put in %rdi.← asm_start.push_str(format!("\tmov rdi, {}\n", p.unwrap()).as_str()); + // First parameter. Put in %rdi. + unwrap!(p); + asm_start.push_str(format!("\tmov rdi, rax\n").as_str()); // rdi ← e.params[0]; }, 1 => { // Second parameter. Put in %rsi. - asm_start.push_str(format!("\tmov rsi, {}\n", p.unwrap()).as_str()); + unwrap!(p); + asm_start.push_str(format!("\tmov rsi, rax\n").as_str()); // rsi ← e.params[1]; }, - 2 => { + 2 => { // Third parameter. Put in %rdx. - asm_start.push_str(format!("\tmov rdx, {}\n", p.unwrap()).as_str()); + unwrap!(p); + asm_start.push_str(format!("\tmov rdx, rax\n").as_str()); // rdx ← e.params[2]; }, 3 => { // Fourth parameter. Put in %rcx. - asm_start.push_str(format!("\tmov rcx, {}\n", p.unwrap()).as_str()); + unwrap!(p); + asm_start.push_str(format!("\tmov rcx, rax\n").as_str()); // rcx ← e.params[3]; }, 4 => { // Fifth parameter. Put in %r8. - asm_start.push_str(format!("\tmov r8, {}\n", p.unwrap()).as_str()); + unwrap!(p); + asm_start.push_str(format!("\tmov r8, rax").as_str()); // r8 ← e.params[4]; }, 5 => { // Sixth parameter. Put in %r9. - asm_start.push_str(format!("\tmov r9, {}\n", p.unwrap()).as_str()); + unwrap!(p); + asm_start.push_str(format!("\tmov r9, rax\n").as_str()); // r9 ← e.params[5]; }, _ => { // Parameters after the sixth parameter are pushed to the stack. - asm_start.push_str(format!("\tpush {}\n", p.unwrap()).as_str()); + unwrap!(p); + asm_start.push_str(format!("\tpush rax\n").as_str()); // STACK_TOP ← e.params[(6+)]; } } @@ -138,16 +149,16 @@ pub fn fasm_codegen(exprs: &Vec, not_a_function: bool) -> String { }, // Define a global variable. - Expr::VarDefinition(e) => { - // Define a 64-bit variable. - asm_data.push_str(format!("\t{} dq {}", e.name, e.value.unwrap()).as_str()); + Expr::GlobalDefinition(e) => { + // Define a 64-bit global variable. + + asm_data.push_str(format!("\t{} dq {}", e.name, e.value).as_str()); }, // Breakpoint. Expr::Breakpoint => { // Write the interrupt for a debugger breakpoint. asm_start.push_str("\tint3\n"); - asm_start.push_str("\txor rax, rax\n"); }, // Return something from a function. @@ -155,8 +166,7 @@ pub fn fasm_codegen(exprs: &Vec, not_a_function: bool) -> String { // Do the operation that should later be returned. asm_start.push_str(fasm_codegen!(fun: &e).as_str()); // Move the return value to rbp + 8. - asm_start.push_str("mov [rbp + 8], rax"); - // 8(%rbp) ← return_value + // [rbp + 8] ← return_value }, // A function defenition. @@ -171,37 +181,42 @@ pub fn fasm_codegen(exprs: &Vec, not_a_function: bool) -> String { Expr::If(e) => { // Increment the temporary variable/function counter. - tmp_counter += 1; // Compare the left and right value. - asm_start.push_str(format!("\tcmp {}, {}\n", e.left.unwrap(), e.right.unwrap()).as_str()); + unwrap!(e.left); + asm_start.push_str("mov rdi, rax"); + unwrap!(e.right); + asm_start.push_str("mov rsi, rax"); + asm_start.push_str(format!("\tcmp rdi, rsi\n").as_str()); // Check what the condition is. match e.cond { COND_OP::EQ => { // If the compared values are equal to each other jump to the temporary function. - asm_start.push_str(format!("je .{}", temp(tmp_counter)).as_str()); + asm_start.push_str(format!("je .{}", temp!()).as_str()); }, COND_OP::NE => { // If the compared values are not equal to eachother jump to the temporary function. - asm_start.push_str(format!("jne .{}", temp(tmp_counter)).as_str()); + asm_start.push_str(format!("jne .{}", temp!()).as_str()); } } // Create the temporary function. - asm_func.push_str(format!(".{}:\n", temp(tmp_counter)).as_str()); + asm_func.push_str(format!(".{}:\n", temp!()).as_str()); asm_func.push_str(fasm_codegen!(fun: &e.action).as_str()); asm_func.push_str("\tret\n"); - } - - _ => unsafe { + }, + Expr::Number(n) => { + asm_func.push_str(format!("\tmov rax, {}\n", n).as_str()) + }, + no => unsafe { // Write some data I randomly typed to your memory because don't going around playing with something that I haven't implemented yet. + println!("{:?} is not. implemented.", no); let mut ptr = 0x00 as *mut f64; ::std::ptr::write(ptr, 124010240120401240.12410240124120401240); }, } - - + } diff --git a/src/lex/tok.rs b/src/lex/tok.rs index 2b45e73..1d4e473 100644 --- a/src/lex/tok.rs +++ b/src/lex/tok.rs @@ -51,6 +51,8 @@ pub enum Token { Fnaf, // fnaf #[token("let")] Let, // let + #[token("global")] + Global, // global #[token("if")] If, // if #[token("else")] @@ -85,7 +87,7 @@ pub enum Token { String, // A string literal. #[regex("[0-9]+", |lex| lex.slice().parse().ok())] Number(u64), // An integer. - #[regex(r#"[^[0-9]^"^-^[ \t\n\f]^\.^=^(^)^{^}.^,^;]+[^"^-^=^\..^[ \t\n\f]^(^)^{^}^,^;]*"#)] + #[regex(r#"[^[0-9]^"^-^[ \t\n\f]^\.^=^(^)^{^}.^,^;^[+-/*%]]+[^"^-^=^\..^[ \t\n\f]^(^)^{^}^,^;^[+-/*%]]*"#)] Identifier, // An identifier. #[token("true")] True, // true @@ -96,7 +98,6 @@ pub enum Token { } pub fn lex_str(this: &str) -> Vec<(Token, &str)> { - println!("\"{}\"", this); let mut buf = Vec::new(); let mut lexer = Token::lexer(this); while let Some(Ok(token)) = lexer.next() { diff --git a/src/main.rs b/src/main.rs index fc7ef6c..f7c2ff1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,12 @@ use logos::Logos; pub mod parse; +macro_rules! arrow { + ($spaces:expr) => { + println!("{}↓", $spaces); + } +} + fn main() { // let fc = fasm_codegen!( // vec![ @@ -45,9 +51,17 @@ fn main() { // println!("{}", fc); - let parsed = "hello(hi)"; + let parsed = "30 * 60"; let mut lexer = Token::lexer(parsed); + + println!("\"{}\"", parsed); + arrow!(" "); println!("{:?}", lex_str(parsed)); - println!("{:?}", parse_fun_call(lexer)); + arrow!(" "); + let parsed = parse_math(lexer); + println!("{:?}", parsed); + arrow!(" "); + println!("{}", fasm_codegen!(&vec![parsed.unwrap()])); } + diff --git a/src/parse/ast.rs b/src/parse/ast.rs index 4414421..e3edb69 100644 --- a/src/parse/ast.rs +++ b/src/parse/ast.rs @@ -1,22 +1,26 @@ use std::rc::Rc; -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Expr<'a> { MathExpr(Math<'a>), FunCall(FunCall<'a>), - FunDefinition(FunDefinition<'a>), - VarDefinition(VarDefinition<'a>), + FunDefinition(Rc>), + GlobalDefinition(Rc>), Return(Vec>), - If(IfCondition<'a>), + If(Rc>), + Var(VarReference<'a>), + Param(ParamReference), + Number(u64), + Breakpoint } // MATH EXPRESSION -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] pub struct Math<'a> { - pub left: &'a Value<'a>, - pub right: &'a Value<'a>, + pub left: Rc>, + pub right: Rc>, pub operator: MathOperator } @@ -31,10 +35,10 @@ pub enum MathOperator { // FUNCTIONS -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct FunCall<'a> { pub name: &'a str, - pub params: Vec>, + pub params: Vec>>, } #[derive(Debug)] @@ -51,7 +55,7 @@ pub struct FunParamDef<'a> { #[derive(Debug)] pub struct FunParamCall<'a> { - pub value: Value<'a>, + pub value: Expr<'a>, } // VARIABLES @@ -59,7 +63,7 @@ pub struct FunParamCall<'a> { #[derive(Debug)] pub struct VarDefinition<'a> { pub name: &'a str, - pub value: Value<'a>, + pub value: u64, } @@ -73,17 +77,12 @@ pub struct ParamReference { pub param_number: u64, } -#[derive(Debug, Copy, Clone)] -pub enum Value<'a> { - Var(VarReference<'a>), - Param(ParamReference), - Number(u64), -} +// CONDITIONS #[derive(Debug)] pub struct IfCondition<'a> { - pub left: Value<'a>, - pub right: Value<'a>, + pub left: Rc>, + pub right: Rc>, pub cond: COND_OP, pub action: Vec> } @@ -94,28 +93,29 @@ pub enum COND_OP { NE, } -impl<'a> Value<'a> { - pub fn unwrap(&self) -> String { - match self { - Value::Param(e) => { - match e.param_number { - 0 => { return "rdi".to_string(); }, - 1 => { return "rsi".to_string(); }, - 2 => { return "rdx".to_string(); }, - 3 => { return "rcx".to_string(); }, - 4 => { return "r8".to_string(); }, - 5 => { return "r9".to_string(); }, - _ => { unimplemented!() } - } - }, +// VALUE +// impl<'a> Value<'a> { +// pub fn unwrap(&self) -> String { +// match self { +// Value::Param(e) => { +// match e.param_number { +// 0 => { return "rdi".to_string(); }, +// 1 => { return "rsi".to_string(); }, +// 2 => { return "rdx".to_string(); }, +// 3 => { return "rcx".to_string(); }, +// 4 => { return "r8".to_string(); }, +// 5 => { return "r9".to_string(); }, +// _ => { unimplemented!() } +// } +// }, - Value::Number(e) => { - return e.to_string(); - }, +// Value::Number(e) => { +// return e.to_string(); +// }, - Value::Var(e) => { - return format!("[{}]", e.name.to_string()); - }, - } - } -} +// Value::Var(e) => { +// return format!("[{}]", e.name.to_string()); +// }, +// } +// } +// } diff --git a/src/parse/parse.rs b/src/parse/parse.rs index d12a7f1..5869da9 100644 --- a/src/parse/parse.rs +++ b/src/parse/parse.rs @@ -1,14 +1,40 @@ use super::ast::*; use crate::lex::tok::*; use logos::Lexer; +use std::rc::Rc; +#[macro_export] macro_rules! unwrap { ($var:expr) => { $var.next().unwrap().unwrap() } } -pub fn parse_var_declaration(mut tokens: Lexer) -> Option { +#[macro_export] +macro_rules! parse_value { + ($parse:expr) => { + parse_value(&($parse.next(), $parse.slice())) + } +} + +pub fn parse_math(mut tokens: Lexer) -> Option { + // Is it a Value? → Is it an operator? → Is it a value? + + if let Some(left) = parse_value!(tokens) { + if let Some(operator) = match_operator(&mut tokens) { + if let Some(right) = parse_value!(tokens) { + let left = Rc::new(left); + let right = Rc::new(right); + + return Some(Expr::MathExpr(Math {left: left, right: right, operator})) + } + } + } + + None +} + +pub fn parse_global_declaration(mut tokens: Lexer) -> Option { let mut tok = None; if unwrap!(tokens) == Let { if unwrap!(tokens) == Identifier { @@ -18,12 +44,7 @@ pub fn parse_var_declaration(mut tokens: Lexer) -> Option { if unwrap!(tokens) == Equal { let temp_token = unwrap!(tokens); if let Number(n) = temp_token { - let value = Value::Number(n); - println!("{:?}", value); - tok = Some(Expr::VarDefinition(VarDefinition {name, value})); - } else if temp_token == Identifier { - let value = Value::Var(VarReference { name: tokens.slice() }); - tok = Some(Expr::VarDefinition(VarDefinition {name, value})); + tok = Some(Expr::GlobalDefinition(Rc::new(VarDefinition {name, value: n}))); } } } @@ -31,14 +52,14 @@ pub fn parse_var_declaration(mut tokens: Lexer) -> Option { tok } -pub fn parse_value<'a>(token: (Option>, &'a str)) -> Option> { - if let Some(Ok(tt)) = token.0 { +pub fn parse_value<'a>(token: &(Option>, &'a str)) -> Option> { + if let Some(Ok(tt)) = &token.0 { let mut value = None; if let Number(n) = tt { - value = Some(Value::Number(n)); - } else if tt == Identifier { - value = Some(Value::Var(VarReference { name: token.1 })); + value = Some(Expr::Number(*n)); + } else if *tt == Identifier { + value = Some(Expr::Var(VarReference { name: token.1 })); } value @@ -58,8 +79,8 @@ pub fn parse_fun_call(mut tokens: Lexer) -> Option { let name = tokens.slice(); if unwrap!(tokens) == LeftParen { let mut params = Vec::new(); - while let Some(value) = parse_value((tokens.next(), tokens.slice())) { - params.push(value); + while let Some(value) = parse_value!(tokens) { + params.push(Rc::new(value)); } tok = Some(Expr::FunCall(FunCall {name, params: params.clone()})); } @@ -67,3 +88,14 @@ pub fn parse_fun_call(mut tokens: Lexer) -> Option { tok } + +pub fn match_operator(tokens: &mut Lexer) -> Option { + match unwrap!(tokens) { + Plus => Some(MathOperator::OP_ADD), + Minus => Some(MathOperator::OP_SUB), + Slash => Some(MathOperator::OP_DIV), + Star => Some(MathOperator::OP_MULT), + Percent => Some(MathOperator::OP_MOD), + _ => None + } +}