Compare commits

...

12 commits

Author SHA1 Message Date
Goren Barak 137d9f5884 Added src/codegen/holeybytes.rs. 2023-12-24 10:44:37 -05:00
Goren Barak e3cdfec0d9 Started working on a holeybytes backend. 2023-12-24 10:43:15 -05:00
Goren Barak 71ed4cea39 Made the frontend for math, actually, completely work. 2023-12-16 10:02:31 -05:00
Goren Barak 77eb521af4 Math works (more)! 2023-12-15 17:15:08 -05:00
Goren Barak ac72d8add8 Math works! 2023-12-15 17:11:58 -05:00
Goren Barak 626f1694f4 Made the backend work for math, working on the frontend 2023-12-15 14:51:09 -05:00
Goren Barak c83b131381 not compiling >:-( 2023-12-11 17:42:45 -05:00
Goren Barak 7d7bac18c6 Still incredibly buggy, but i need to commit something to git.
I'm going to fix the problem soon trust me :3
2023-12-09 15:35:48 -05:00
Goren Barak fba9dded42 Started implementing an operation queue. 2023-12-01 18:55:35 -05:00
Goren Barak dd1bc0b478 Hopefully made math recursively work and added FasmCodegen struct. 2023-12-01 16:58:35 -05:00
Goren Barak 1a8d7498e5 Merge branch 'recursive' 2023-11-30 13:01:12 -05:00
Goren Barak 6e7b286458 Added LICENSE file 2023-11-29 11:18:56 -05:00
19 changed files with 623 additions and 837 deletions

View file

@ -2,6 +2,7 @@
name = "skylang"
version = "0.1.0"
edition = "2021"
channel = "nightly"
[lib]
proc-macro = true

24
LICENSE Normal file
View file

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>

159
TAGS~
View file

@ -1,159 +0,0 @@
Cargo.lock,0
Cargo.toml,0
README.md,130
# ![SkyLang](.images/slang_logo_dark_transparent_not_motto.png)![SkyLang](.images/slang_logo_dark_transparent_not_motto.png)1,0
src/codegen/fasm.rs,91
pub fn fasm_codegen(exprs: &Vec<Expr>, not_a_function: bool) -> String {fasm_codegen3,27
src/codegen/fasmarm.rs,0
src/codegen/mod.rs,23
pub mod fasm;fasm1,0
src/lex/mod.rs,47
pub mod tok;tok1,0
pub mod parse;parse2,13
src/lex/parse.rs,755
pub fn match_single_char<'a>(word: &'a str) -> Option<Token<'a>> {match_single_char6,40
macro_rules! tok {tok7,107
pub fn match_keyword<'a>(word: &'a str) -> Option<Token<'a>> {match_keyword38,697
macro_rules! tok {tok39,760
pub fn match_two_char<'a>(word: &'a str) -> Option<Token<'a>> {match_two_char66,1310
macro_rules! tok {tok67,1374
pub fn match_string_literal<'a>(word: &'a str) -> Option<Token<'a>> {match_string_literal85,1681
macro_rules! tok {tok86,1751
pub fn match_int_literal<'a>(word: &'a str) -> Option<Token<'a>> {match_int_literal114,2191
macro_rules! tok {tok115,2258
pub fn match_identifier<'a>(word: &'a str) -> Option<Token<'a>> {match_identifier134,2562
macro_rules! tok {tok135,2628
src/lex/tok.rs,2268
pub struct Token<'a> {Token6,79
tt: TokenType,tt7,102
word: &'a str,word8,121
pub enum TokenType {TokenType12,160
EOF,EOF13,181
Semicolon, // ;Semicolon16,222
Equal, // =Equal17,242
LeftParen, // (LeftParen18,258
RightParen, // )RightParen19,278
LeftBrace, // {LeftBrace20,299
RightBrace, // }RightBrace21,319
Comma, // ,Comma22,340
Dot, // .Dot23,356
Minus, // -Minus24,370
Plus, // +Plus25,386
Slash, // /Slash26,401
Star, // *Star27,417
Percent, // %Percent28,432
Bang, // !Bang29,450
Colon, // :Colon30,465
Less, // <Less31,481
Greater, // >Greater32,496
Fn, // fnFn35,531
Let, // letLet36,546
If, // ifIf37,562
Else, // elseElse38,577
While, // whileWhile39,595
Elif, // elifElif40,615
Return, // returnReturn41,633
For, // forFor42,655
In, // inIn43,671
Break, // breakBreak44,686
Continue, // continueContinue45,706
EqualEqual, // ==EqualEqual48,761
BangEqual, // !=BangEqual49,784
LessEqual, // <=LessEqual50,806
GreaterEqual, // >=GreaterEqual51,828
String, // A string literal.String54,873
Number, // An integer.Number55,906
Identifier, // An identifier.Identifier56,933
True, // trueTrue57,967
False, // falseFalse58,985
Null, // NoneNull59,1005
Error, // A syntax error.Error62,1037
pub struct Lexer<'a> {Lexer66,1087
source: &'a str,source67,1110
tokens: Vec<Token<'a>>,tokens68,1131
current: usize,current69,1159
after: &'a strafter70,1179
impl<'a> Lexer<'a> {Lexer73,1201
pub fn new() -> Self {new74,1222
impl<'a> std::iter::Iterator for Lexer<'a> {Lexer84,1386
type Item = Option<char>;Item85,1431
fn next(&mut self) -> Option<Self::Item> {next87,1462
impl<'a> From<&'a str> for Lexer<'a> {Lexer92,1579
fn from(value: &'a str) -> Self {from93,1618
impl<'a> From<&'a std::string::String> for Lexer<'a> {Lexer103,1800
fn from(value: &'a std::string::String) -> Self {from104,1855
impl<'a> Token<'a> {Token114,2057
pub fn new(tt: TokenType, word: &'a str) -> Self {new115,2078
pub fn empty() -> Self {empty122,2171
src/main.rs,102
pub mod lex;lex3,21
pub mod codegen;codegen4,34
pub mod parse;parse7,106
fn main() {main9,122
src/parse/ast.rs,2125
pub enum Expr<'a> {Expr2,17
MathExpr(Math<'a>),MathExpr3,37
FunCall(FunCall<'a>),FunCall4,61
FunDefinition(FunDefinition<'a>),FunDefinition5,87
VarDefinition(VarDefinition<'a>),VarDefinition6,125
Return(Value<'a>),Return7,163
If(IfStatement<'a>),If8,186
BreakpointBreakpoint9,211
pub struct Math<'a> {Math15,279
pub left: &'a Value<'a>,left16,301
pub right: &'a Value<'a>,right17,330
pub operator: MathOperatoroperator18,360
pub enum MathOperator {MathOperator22,424
OP_ADD, // AdditionOP_ADD23,448
OP_SUB, // SubtractionOP_SUB24,472
OP_DIV, // DivisionOP_DIV25,499
OP_MULT, // MultiplicationOP_MULT26,523
OP_MOD, // ModuloOP_MOD27,554
pub struct FunCall<'a> {FunCall33,610
pub name: &'a str,name34,635
pub params: Vec<Value<'a>>,params35,658
pub struct FunDefinition<'a> {FunDefinition39,710
pub name: &'a str,name40,741
pub contents: Vec<Expr<'a>>,contents41,764
pub struct FunParamDef<'a> {FunParamDef45,817
name: &'a str,name46,846
number: u64,number47,865
pub struct FunParamCall<'a> {FunParamCall51,902
pub value: Value<'a>,value52,932
pub struct VarDefinition<'a> {VarDefinition58,992
pub name: &'a str,name59,1023
pub value: Value<'a>,value60,1046
pub struct VarReference<'a> {VarReference65,1106
pub name: &'a str,name66,1136
pub struct ParamReference {ParamReference70,1192
pub param_number: u64,param_number71,1220
pub enum Value<'a> {Value75,1280
Var(VarReference<'a>),Var76,1301
Param(ParamReference),Param77,1328
Number(u64),Number78,1355
pub struct IfStatement<'a> {IfStatement82,1392
pub condition: Condition<'a>,condition83,1421
pub if_true: Vec<Expr<'a>>,if_true84,1455
pub struct Condition<'a> {Condition88,1507
pub left: Value<'a>,left89,1534
pub right: Value<'a>,right90,1559
pub between: COND_OP,between91,1585
pub enum COND_OP {COND_OP95,1631
EQ,EQ96,1650
NE,NE97,1658
impl<'a> Value<'a> {Value100,1669
pub fn unwrap(&self) -> String {unwrap101,1690
src/parse/mod.rs,21
pub mod ast;ast1,0

View file

@ -1,66 +0,0 @@
#![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()]));
}

View file

@ -1,234 +1,256 @@
use crate::parse::ast::*;
use std::rc::Rc;
use skylang::temp;
use std::rc::Rc;
#[macro_export]
macro_rules! fasm_codegen {
// Macro to make calling fasm_codegen function easier.
($exprs:expr) => {
fasm_codegen($exprs, true)
};
#[derive(Debug)]
pub struct FasmCodegen;
(fun: $exprs:expr) => {
fasm_codegen($exprs, false)
}
}
pub fn fasm_codegen(exprs: &Vec<Expr>, not_a_function: bool) -> String {
// 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 {
asm_start.push_str("format ELF64 executable 3\n");
asm_start.push_str("segment readable executable\n");
asm_start.push_str("entry _start\n");
asm_start.push_str("_start:\n");
asm_data.push_str("\nsegment readable writable\n");
impl FasmCodegen {
pub fn new() -> Self {
FasmCodegen
}
// 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) => {
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 => {
asm_start.push_str("\tadd r10, r11\n");
asm_start.push_str("\tmov rax, r10\n");
// r10 ← r10 + r11; rax ← r10;
// The sum will now be stored in the %rax register.
},
// If the operator is multiplication.
MathOperator::OP_MULT => {
asm_start.push_str("\timul r10, r11\n");
asm_start.push_str("\tmov rax, r10\n");
// r10 ← r10 * r11; rax ← r10;
// The product will now be stored in the %rax register.
},
// If the operator is division.
MathOperator::OP_DIV => {
asm_start.push_str("\tmov rax, r10\n");
asm_start.push_str("\txor rdx, rdx\n");
asm_start.push_str("\tidiv r11\n");
// rax ← r10; rdx ← 0; rax ← concat(rax, rdx) / r11;
// The quotient will now be stored in the %rax register.
},
// If the operators is subtraction.
MathOperator::OP_SUB => {
asm_start.push_str("\tsub r10, r11\n");
asm_start.push_str("\tmov rax, r10\n");
// r10 ← r10 - r11; rax ← r10;
// The difference will now be stored in the %rax register.
},
// If the operator is modulo.
MathOperator::OP_MOD => {
asm_start.push_str("\tmov rax, r10\n");
asm_start.push_str("\txor rdx, rdx\n");
asm_start.push_str("\tidiv r11\n");
asm_start.push_str("\tmov rax, rdx\n");
// rax ← r10; rdx ← 0; rdx ← concat(rax, rdx) % r11; rax ← rdx;
// The remainder will now be stored in the %rax register.
}
}
},
pub fn fasm_codegen(&mut self, exprs: &Vec<Expr>, not_a_function: bool) -> String {
macro_rules! fasm_codegen {
// Macro to make calling fasm_codegen function easier.
($exprs:expr) => {{
self.fasm_codegen($exprs, true)
}};
(fun: $exprs:expr) => {{
self.fasm_codegen($exprs, false)
}};
}
// 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 the expression is a function call.
Expr::FunCall(e) => {
for (i, p) in e.params.iter().enumerate() {
match i {
0 => {
// First parameter. Put in %rdi.
unwrap!(p);
asm_start.push_str(format!("\tmov rdi, rax\n").as_str());
// rdi ← e.params[0];
// If not_a_function, push necessary headers to the asm_start variable.
if not_a_function {
asm_start.push_str("format ELF64 executable 3\n");
asm_start.push_str("segment readable executable\n");
asm_start.push_str("entry _start\n");
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) => {
unwrap!(e.right);
asm_start.push_str("\tpush rax\n");
unwrap!(e.left);
asm_start.push_str("\tpush rax\n");
match e.operator {
// If the operator is addition.
MathOperator::OP_ADD => {
asm_start.push_str("\tpop r10\n");
asm_start.push_str("\tpop r11\n");
asm_start.push_str("\tadd r10, r11\n");
asm_start.push_str("\tmov rax, r10\n");
// r10 ← r10 + r11; rax ← r10;
// The sum will now be stored in the %rax register.
},
// If the operator is multiplication.
MathOperator::OP_MULT => {
asm_start.push_str("\tpop r10\n");
asm_start.push_str("\tpop r11\n");
asm_start.push_str("\timul r10, r11\n");
asm_start.push_str("\tmov rax, r10\n");
1 => {
// Second parameter. Put in %rsi.
unwrap!(p);
asm_start.push_str(format!("\tmov rsi, rax\n").as_str());
// rsi ← e.params[1];
// r10 ← r10 * r11; rax ← r10;
// The product will now be stored in the %rax register.
},
2 => {
// Third parameter. Put in %rdx.
unwrap!(p);
asm_start.push_str(format!("\tmov rdx, rax\n").as_str());
// rdx ← e.params[2];
// If the operator is division.
MathOperator::OP_DIV => {
asm_start.push_str("\tpop r10\n");
asm_start.push_str("\tpop r11\n");
asm_start.push_str("\tmov rax, r10\n");
asm_start.push_str("\txor rdx, rdx\n");
asm_start.push_str("\tidiv r11\n");
// rax ← r10; rdx ← 0; rax ← concat(rax, rdx) / r11;
// The quotient will now be stored in the %rax register.
},
// If the operators is subtraction.
MathOperator::OP_SUB => {
asm_start.push_str("\tpop r10\n");
asm_start.push_str("\tpop r11\n");
asm_start.push_str("\tsub r10, r11\n");
asm_start.push_str("\tmov rax, r10\n");
3 => {
// Fourth parameter. Put in %rcx.
unwrap!(p);
asm_start.push_str(format!("\tmov rcx, rax\n").as_str());
// rcx ← e.params[3];
// r10 ← r10 - r11; rax ← r10;
// The difference will now be stored in the %rax register.
},
4 => {
// Fifth parameter. Put in %r8.
unwrap!(p);
asm_start.push_str(format!("\tmov r8, rax").as_str());
// r8 ← e.params[4];
},
5 => {
// Sixth parameter. Put in %r9.
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.
unwrap!(p);
asm_start.push_str(format!("\tpush rax\n").as_str());
// STACK_TOP ← e.params[(6+)];
// If the operator is modulo.
MathOperator::OP_MOD => {
asm_start.push_str("\tpop r10\n");
asm_start.push_str("\tpop r11\n");
asm_start.push_str("\tmov rax, r10\n");
asm_start.push_str("\txor rdx, rdx\n");
asm_start.push_str("\tidiv r11\n");
asm_start.push_str("\tmov rax, rdx\n");
// rax ← r10; rdx ← 0; rdx ← concat(rax, rdx) % r11; rax ← rdx;
// The remainder will now be stored in the %rax register.
}
}
}
},
// Call the function.
asm_start.push_str(format!("\tcall {}\n", e.name).as_str());
},
// If the expression is a function call.
Expr::FunCall(e) => {
for (i, p) in e.params.iter().enumerate() {
match i {
0 => {
// First parameter. Put in %rdi.
unwrap!(p);
asm_start.push_str("\tmov rdi, rax\n".to_string().as_str());
// rdi ← e.params[0];
},
// Define a global variable.
Expr::GlobalDefinition(e) => {
// Define a 64-bit global variable.
asm_data.push_str(format!("\t{} dq {}", e.name, e.value).as_str());
},
1 => {
// Second parameter. Put in %rsi.
unwrap!(p);
asm_start.push_str("\tmov rsi, rax\n".to_string().as_str());
// rsi ← e.params[1];
},
// Breakpoint.
Expr::Breakpoint => {
// Write the interrupt for a debugger breakpoint.
asm_start.push_str("\tint3\n");
},
2 => {
// Third parameter. Put in %rdx.
unwrap!(p);
asm_start.push_str("\tmov rdx, rax\n".to_string().as_str());
// rdx ← e.params[2];
},
// Return something from a function.
Expr::Return(e) => {
// 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.
// [rbp + 8] ← return_value
},
3 => {
// Fourth parameter. Put in %rcx.
unwrap!(p);
asm_start.push_str("\tmov rcx, rax\n".to_string().as_str());
// rcx ← e.params[3];
},
// A function defenition.
Expr::FunDefinition(e) => {
// In x86-64 assembly, a function is defined as <function_name>:. Push this to the `asm_func`.
asm_func.push_str(format!("{}:\n", e.name).as_str());
// Call the function itself specifying that you are defining a function, and push the returned value to `asm_func`.
asm_func.push_str(fasm_codegen!(fun: &e.contents).as_str());
// Use the ret instruction to return from the procedure.
asm_func.push_str("\tret\n");
},
4 => {
// Fifth parameter. Put in %r8.
unwrap!(p);
asm_start.push_str("\tmov r8, rax".to_string().as_str());
// r8 ← e.params[4];
},
Expr::If(e) => {
// Increment the temporary variable/function counter.
// Compare the left and right value.
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!()).as_str());
},
5 => {
// Sixth parameter. Put in %r9.
unwrap!(p);
asm_start.push_str("\tmov r9, rax\n".to_string().as_str());
// r9 ← e.params[5];
},
COND_OP::NE => {
// If the compared values are not equal to eachother jump to the temporary function.
asm_start.push_str(format!("jne .{}", temp!()).as_str());
_ => {
// Parameters after the sixth parameter are pushed to the stack.
unwrap!(p);
asm_start.push_str("\tpush rax\n".to_string().as_str());
// STACK_TOP ← e.params[(6+)];
}
}
}
}
// Create the temporary function.
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");
// Call the function.
asm_start.push_str(format!("\tcall {}\n", e.name).as_str());
},
},
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);
},
// Define a global variable.
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");
},
// Return something from a function.
Expr::Return(e) => {
// 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.
// [rbp + 8] ← return_value
},
// A function defenition.
Expr::FunDefinition(e) => {
// In x86-64 assembly, a function is defined as <function_name>:. Push this to the `asm_func`.
asm_func.push_str(format!("{}:\n", e.name).as_str());
// Call the function itself specifying that you are defining a function, and push the returned value to `asm_func`.
asm_func.push_str(fasm_codegen!(fun: &e.contents).as_str());
// Use the ret instruction to return from the procedure.
asm_func.push_str("\tret\n");
},
Expr::If(e) => {
// Increment the temporary variable/function counter.
// Compare the left and right value.
unwrap!(e.left);
asm_start.push_str("mov rdi, rax");
unwrap!(e.right);
asm_start.push_str("mov rsi, rax");
asm_start.push_str("\tcmp rdi, rsi\n".to_string().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!()).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!()).as_str());
}
}
// Create the temporary function.
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");
},
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 ptr = std::ptr::null_mut::<f64>();
::std::ptr::write(ptr, 124010240120401240.12410240124120401240);
},
}
}
}
if not_a_function {
// Use the exit syscall to leave the program. If you don't do this, you will get a segmentation fault.
asm_start.push_str("\tmov rax, 60 ; 60 is the system call number for exit.\n");
asm_start.push_str("\txor rdi, rdi ; 0 is the exit code we want.\n");
asm_start.push_str("\tsyscall ; this is the instruction to actually perform the system call.\n");
if not_a_function {
// Use the exit syscall to leave the program. If you don't do this, you will get a segmentation fault.
asm_start.push_str("\tmov rax, 60 ; 60 is the system call number for exit.\n");
asm_start.push_str("\txor rdi, rdi ; 0 is the exit code we want.\n");
asm_start.push_str("\tsyscall ; this is the instruction to actually perform the system call.\n");
}
// Get the final `asm` string derived from all of the other strings that we have manipulated (finally!).
let asm = format!("{}{}{}", asm_start, asm_func, asm_data);
// Return the final `asm` string.
asm
}
// Get the final `asm` string derived from all of the other strings that we have manipulated (finally!).
let asm = format!("{}{}{}", asm_start, asm_func, asm_data);
// Return the final `asm` string.
asm
}

View file

274
src/codegen/holeybytes.rs Normal file
View file

@ -0,0 +1,274 @@
use crate::parse::ast::*;
use skylang::temp;
use std::rc::Rc;
use std::collections::HashMap;
#[derive(Debug)]
pub struct HbCodegen {
pc: u32,
functions: HashMap<String, u32>,
globals: HashMap<String, u64>,
}
impl HbCodegen {
pub fn new() -> Self {
HbCodegen {
pc: 0,
functions: HashMap::new(),
globals: HashMap::new()
}
}
pub fn hb_codegen(&mut self, exprs: &Vec<Expr>) -> &[u8] {
let mut gen: Vec<u8> = Vec::new();
macro_rules! unwrap {
($item:expr) => {
ins!({ self.hb_codegen(&vec![Rc::unwrap_or_clone($item)]) });
};
(norc $item:expr) => {
ins!(*{ self.hb_codegen(&vec![$item]) });
}
}
macro_rules! ins {
($ins:expr) => {
let ins = $ins;
let new_pc = self.pc.wrapping_add(ins.len() as u32);
gen.extend_from_slice(&ins);
self.pc = new_pc;
};
($($ins:expr);+) => {
$(
let ins = { $ins };
let new_pc = self.pc.wrapping_add(ins.len() as u32);
gen.extend_from_slice(&ins);
self.pc = new_pc;
)+
}
}
// 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) => {
unwrap!(e.right);
// st r1, r254, 0, 8; addi64 r254, r254, 8;
ins!([0x4e, 1, 254, 0, 8, 0x30, 254, 254, 8]);
unwrap!(e.left);
// st r1, r254, 0, 8; addi64 r254, r254, 8;
ins!([0x4e, 1, 254, 0, 8, 0x30, 254, 254, 8]);
match e.operator {
// If the operator is addition.
MathOperator::OP_ADD => {
// addi64 r254, r254, -8 (two's complement 0b11111000); ld r33, r254, 0, 8;
ins!([0x40, 254, 254, 0b11111000, 0x4d, 33, 254, 0, 8]);
// addi64 r254, r254, -8 (two's complement 0b11111000); ld r34, r254, 0, 8;
ins!([0x40, 254, 254, 0b11111000, 0x4d, 34, 254, 0, 8]);
// add64 r1, r32, r33
ins!([0x06, 1, 32, 33]);
},
// If the operator is multiplication.
MathOperator::OP_MULT => {
// addi64 r254, r254, -8 (two's complement 0b11111000); ld r33, r254, 0, 8;
ins!([0x40, 254, 254, 0b11111000, 0x4d, 33, 254, 0, 8]);
// addi64 r254, r254, -8 (two's complement 0b11111000); ld r34, r254, 0, 8;
ins!([0x40, 254, 254, 0b11111000, 0x4d, 34, 254, 0, 8]);
// mul64 r1, r33, r34
ins!([0x0e, 1, 33, 34]);
},
// If the operator is division.
MathOperator::OP_DIV => {
// addi64 r254, r254, -8 (two's complement 0b11111000); ld r33, r254, 0, 8;
ins!([0x40, 254, 254, 0b11111000, 0x4d, 33, 254, 0, 8]);
// addi64 r254, r254, -8 (two's complement 0b11111000); ld r34, r254, 0, 8;
ins!([0x40, 254, 254, 0b11111000, 0x4d, 34, 254, 0, 8]);
// fdiv64 r1, r33, r34
ins!([0x65, 1, 33, 34]);
},
// If the operators is subtraction.
MathOperator::OP_SUB => {
// addi64 r254, r254, -8 (two's complement 0b11111000); ld r33, r254, 0, 8;
ins!([0x40, 254, 254, 0b11111000, 0x4d, 33, 254, 0, 8]);
// addi64 r254, r254, -8 (two's complement 0b11111000); ld r34, r254, 0, 8;
ins!([0x40, 254, 254, 0b11111000, 0x4d, 34, 254, 0, 8]);
// sub64 r1, r33, r34
ins!([0x0a, 1, 33, 34]);
},
// If the operator is modulo.
MathOperator::OP_MOD => {
// addi64 r254, r254, -8 (two's complement 0b11111000); ld r33, r254, 0, 8;
ins!([0x40, 254, 254, 0b11111000, 0x4d, 33, 254, 0, 8]);
// addi64 r254, r254, -8 (two's complement 0b11111000); ld r34, r254, 0, 8;
ins!([0x40, 254, 254, 0b11111000, 0x4d, 34, 254, 0, 8]);
// dirs64 r2, r1, r33, r34
}
}
},
// If the expression is a function call.
Expr::FunCall(e) => {
for (i, p) in e.params.iter().enumerate() {
match i {
0 => {
unwrap!(*p);
// cp r2, r1
ins!([0x46, 2, 1]);
},
1 => {
unwrap!(*p);
// cp r3, r1
ins!([0x46, 3, 1]);
},
2 => {
unwrap!(*p);
// cp r4, r1
ins!([0x46, 4, 1]);
},
3 => {
unwrap!(*p);
// cp r5, r1
ins!([0x46, 5, 1]);
},
4 => {
unwrap!(*p);
// cp r6, r1
ins!([0x46, 6, 1]);
},
5 => {
unwrap!(*p);
// cp r7, r1
ins!([0x46, 7, 1]);
},
6 => {
unwrap!(*p);
// cp r8, r1
ins!([0x46, 8, 1]);
},
7 => {
unwrap!(*p);
// cp r9, r1
ins!([0x46, 9, 1]);
},
8 => {
unwrap!(*p);
// cp r10, r1
ins!([0x46, 10, 1]);
},
9 => {
unwrap!(*p);
// cp r11, r1
ins!([0x46, 11, 1]);
},
_ => {
println!("More than ten parameters are currently not supported.");
std::process::exit(1);
}
}
}
ins!([0x53]; unsafe { std::mem::transmute::<u32, [u8; 4]>(self.pc.wrapping_sub(self.functions[e.name])) });
},
// Define a global variable.
Expr::GlobalDefinition(e) => {
// Define a 64-bit global variable.
println!("Global variables are currently unsupported.");
std::process::exit(1);
},
// Breakpoint.
Expr::Breakpoint => {
// Write the interrupt for a debugger breakpoint.
ins!([0]);
},
// Return something from a function.
Expr::Return(e) => {
// Do the operation that should later be returned.
println!("Returns are currently not supported, (i was too lazy to implement)");
std::process::exit(1);
},
// A function defenition.
Expr::FunDefinition(e) => {
self.functions.insert(e.name.to_owned(), self.pc);
ins!(&self.hb_codegen(&e.contents).to_vec());
},
Expr::If(e) => {
// Increment the temporary variable/function counter.
// Compare the left and right value.
unwrap!(e.left);
// st r1, r254, 0, 8; addi64 r254, r254, 8;
ins!([0x4e, 1, 254, 0, 8, 0x30, 254, 254, 8]);
unwrap!(e.right);
// st r1, r254, 0, 8; addi64 r254, r254, 8;
ins!([0x4e, 1, 254, 0, 8, 0x30, 254, 254, 8]);
let action = self.pc;
ins!(&self.hb_codegen(&e.action).to_vec());
// 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.
ins!([0x56]; unsafe { std::mem::transmute::<u32, [u8; 4]>(self.pc.wrapping_sub(action)) });
},
COND_OP::NE => {
// If the compared values are not equal to eachother jump to the temporary function.
ins!([0x57]; unsafe { std::mem::transmute::<u32, [u8; 4]>(self.pc.wrapping_sub(action)) });
}
}
},
Expr::Number(n) => {
ins!([0x4b, 1]; unsafe { ::core::mem::transmute::<u64, [u8; 8]>(*n) });
},
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. prepare to be destroyed >:-(", no);
let ptr = std::ptr::null_mut::<f64>();
::std::ptr::write(ptr, 124010240120401240.12410240124120401240);
},
}
}
&gen
}
}

View file

@ -1 +1,2 @@
pub mod holeybytes;
pub mod fasm;

View file

View file

@ -1 +0,0 @@
pub mod tok;

View file

@ -1,149 +0,0 @@
#![allow(unused)]
use super::tok::*;
fn check_single_char<'a>(word: &'a str) -> Option<Token<'a>> {
macro_rules! tok {
($tt:expr) => {
Some(Token::new($tt, word))
};
};
let tok = match word {
";" => tok!(Semicolon),
"=" => tok!(Equal),
"(" => tok!(LeftParen),
")" => tok!(RightParen),
"{" => tok!(LeftBrace),
"}" => tok!(RightBrace),
"," => tok!(Comma),
"." => tok!(Dot),
"-" => tok!(Minus),
"+" => tok!(Plus),
"/" => tok!(Slash),
"*" => tok!(Star),
"%" => tok!(Percent),
"!" => tok!(Bang),
":" => tok!(Colon),
"<" => tok!(Less),
">" => tok!(Greater),
_ => None
};
tok
}
fn check_keyword<'a>(word: &'a str) -> Option<Token<'a>> {
macro_rules! tok {
($tt:expr) => {
Some(Token::new($tt, word))
};
};
let tok = match word {
"fn" => tok!(Fn),
"let" => tok!(Let),
"if" => tok!(If),
"else" => tok!(Else),
"while" => tok!(While),
"elif" => tok!(Elif),
"return" => tok!(Return),
"for" => tok!(For),
"in" => tok!(In),
"break" => tok!(Break),
"continue" => tok!(Continue),
"true" => tok!(True),
"false" => tok!(False),
_ => None
};
tok
}
fn check_two_char<'a>(word: &'a str) -> Option<Token<'a>> {
macro_rules! tok {
($tt:expr) => {
Some(Token::new($tt, word))
};
};
let tok = match word {
"==" => tok!(EqualEqual),
"!=" => tok!(BangEqual),
"<=" => tok!(LessEqual),
">=" => tok!(GreaterEqual),
_ => None
};
tok
}
fn match_string_literal<'a>(word: &'a str) -> Option<Token<'a>> {
macro_rules! tok {
($tt:expr) => {
Some(Token::new($tt, word))
};
};
let chars = word.chars();
if word.starts_with("\"") {
while let Some(char) = chars.next() {
if char == '\"' {
return tok!(String);
}
}
}
if word.starts_with("\'") {
while let Some(char) = chars.next() {
if char == '\'' {
return tok!(String);
}
}
}
None
}
fn match_int_literal<'a>(word: &'a str) -> Option<Token<'a>> {
macro_rules! tok {
($tt:expr) => {
Some(Token::new($tt, word))
};
};
let chars = word.chars();
while let Some(char) = chars.next() {
if char.is_digit(10) {
return tok!(Number);
} else {
return None;
}
}
None
}
fn match_identifier<'a>(word: &'a str) -> Option<Token<'a>> {
macro_rules! tok {
($tt:expr) => {
Some(Token::new($tt, word))
};
};
let chars = word.chars();
if chars.next().is_ascii_alphabetic() {
while let Some(char) = chars.next() {
if chars.next().is_ascii() {
}
}
}
}

View file

@ -1,11 +1,12 @@
#![allow(unused)]
use std::string::String;
use logos::Logos;
use logos::Lexer;
use core::iter::Peekable;
pub use Token::*;
#[derive(Debug, Logos, PartialEq, Eq)]
#[derive(Debug, Logos, PartialEq, Eq, Clone)]
#[logos(skip r"[ \t\n\f]+")]
pub enum Token {
// SINGLE CHARACTER TOKENS
@ -84,11 +85,11 @@ pub enum Token {
// LITERALS
#[regex(r#"("[^"]*")|('[^']*')"#)]
String, // A string literal.
StringLiteral, // 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]^(^)^{^}^,^;^[+-/*%]]*"#)]
Identifier, // An identifier.
Number(u64), // An integer.
#[regex(r#"[^[0-9]^"^-^[ \t\n\f]^\.^=^(^)^{^}.^,^;^[+-/*%]]+[^"^-^=^\..^[ \t\n\f]^(^)^{^}^,^;^[+-/*%]]*"#, |lex| lex.slice().to_owned())]
Identifier(String), // An identifier.
#[token("true")]
True, // true
#[token("false")]
@ -106,3 +107,51 @@ pub fn lex_str(this: &str) -> Vec<(Token, &str)> {
buf
}
impl std::fmt::Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Semicolon => write!(f, ";"),
Equal => write!(f, "="),
LeftParen => write!(f, "("),
RightParen => write!(f, ")"),
LeftBrace => write!(f, "{{"),
RightBrace => write!(f, "}}"),
Comma => write!(f, ","),
Dot => write!(f, "."),
Minus => write!(f, "-"),
Plus => write!(f, "+"),
Slash => write!(f, "/"),
Star => write!(f, "*"),
Percent => write!(f, "%"),
Bang => write!(f, "!"),
Colon => write!(f, ":"),
Less => write!(f, "<"),
Greater => write!(f, ">"),
Pipe => write!(f, "|"),
Fnaf => write!(f, "fnaf"),
Let => write!(f, "let"),
Global => write!(f, "global"),
If => write!(f, "if"),
Else => write!(f, "else"),
While => write!(f, "while"),
Elif => write!(f, "elif"),
Return => write!(f, "return"),
For => write!(f, "for"),
In => write!(f, "in"),
Break => write!(f, "break"),
Continue => write!(f, "continue"),
EqualEqual => write!(f, "=="),
BangEqual => write!(f, "!="),
LessEqual => write!(f, "<="),
GreaterEqual => write!(f, ">="),
StringLiteral => write!(f, "string"),
Number(n) => write!(f, "{}", n),
Identifier(i) => write!(f, "{}", i),
True => write!(f, "true"),
False => write!(f, "false"),
Null => write!(f, "none"),
}
}
}

View file

@ -1,124 +0,0 @@
#![allow(unused)]
pub use TokenType::*;
use super::parse::*;
#[derive(Debug)]
pub struct Token<'a> {
tt: TokenType,
word: &'a str,
}
#[derive(Debug)]
pub enum TokenType {
EOF,
// SINGLE CHARACTER TOKENS
Semicolon, // ;
Equal, // =
LeftParen, // (
RightParen, // )
LeftBrace, // {
RightBrace, // }
Comma, // ,
Dot, // .
Minus, // -
Plus, // +
Slash, // /
Star, // *
Percent, // %
Bang, // !
Colon, // :
Less, // <
Greater, // >
// KEYWORDS
Fn, // fn
Let, // let
If, // if
Else, // else
While, // while
Elif, // elif
Return, // return
For, // for
In, // in
Break, // break
Continue, // continue
// TWO CHARACTER TOKENS
EqualEqual, // ==
BangEqual, // !=
LessEqual, // <=
GreaterEqual, // >=
// LITERALS
String, // A string literal.
Number, // An integer.
Identifier, // An identifier.
True, // true
False, // false
Null, // None
// ERROR
Error, // A syntax error.
}
#[derive(Debug)]
pub struct Lexer<'a> {
source: &'a str,
tokens: Vec<Token<'a>>,
current: usize,
after: &'a str
}
impl<'a> Lexer<'a> {
pub fn new() -> Self {
Lexer {
source: "",
tokens: Vec::new(),
current: 0,
after: ""
}
}
}
impl<'a> std::iter::Iterator for Lexer<'a> {
}
impl<'a> From<&'a str> for Lexer<'a> {
fn from(value: &'a str) -> Self {
Lexer {
source: value,
tokens: Vec::new(),
current: 0,
after: value
}
}
}
impl<'a> From<&'a std::string::String> for Lexer<'a> {
fn from(value: &'a std::string::String) -> Self {
Lexer {
source: value.as_str(),
tokens: Vec::new(),
current: 0,
after: value.as_str()
}
}
}
impl<'a> Token<'a> {
pub fn new(tt: TokenType, word: &'a str) -> Self {
Token {
tt,
word
}
}
pub fn empty() -> Self {
Token {
tt: EOF,
word: ""
}
}
}

View file

@ -1,10 +1,12 @@
#![allow(warnings)]
#![feature(unsized_locals)]
#![feature(arc_unwrap_or_clone)]
#![feature(associated_type_bounds)]
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;
@ -17,51 +19,17 @@ macro_rules! arrow {
}
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);
let mut args = std::env::args();
let (_, parsed) = (args.next(), args.next().unwrap());
let mut lexer = Token::lexer(parsed.as_str());
println!("\"{}\"", parsed);
arrow!(" ");
println!("{:?}", lex_str(parsed));
println!("{:?}", lex_str(parsed.as_str()));
arrow!(" ");
let parsed = parse_math(lexer);
println!("{:?}", parsed);
arrow!(" ");
println!("{}", fasm_codegen!(&vec![parsed.unwrap()]));
let mut code = FasmCodegen::new();
println!("{}", code.fasm_codegen(&vec![parsed.unwrap()], true));
}

View file

@ -1,5 +0,0 @@
pub mod lex;
fn main() {
println!("{:?}", lex::parse::match_identifier("goren-"));
}

View file

View file

View file

@ -10,92 +10,43 @@ macro_rules! unwrap {
}
}
#[macro_export]
macro_rules! parse_value {
($parse:expr) => {
parse_value(&($parse.next(), $parse.slice()))
pub fn expect_number(n: Option<Result<Token, ()>>) -> Expr<'static> {
match n {
Some(Ok(Number(res))) => Expr::Number(res),
Some(Ok(tok)) => {
println!("Expected a number, got: {}", tok);
std::process::exit(1);
}
_ => {
println!("Expected a number, got EOF");
std::process::exit(1);
}
}
}
pub fn parse_math(mut tokens: Lexer<Token>) -> Option<Expr> {
// 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}))
}
}
let mut left = expect_number(tokens.next());
loop {
let op = tokens.next();
if !match_operator(&op).is_some() { break }
let right = expect_number(tokens.next());
left = Expr::MathExpr(Math {left: Rc::new(left), right: Rc::new(right), operator: match_operator(&op)?});
}
Some(left)
}
pub fn match_operator(token: &Option<Result<Token, ()>>) -> Option<MathOperator> {
if let Some(Ok(token)) = token {
return match token {
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
};
}
None
}
pub fn parse_global_declaration(mut tokens: Lexer<Token>) -> Option<Expr> {
let mut tok = None;
if unwrap!(tokens) == Let {
if unwrap!(tokens) == Identifier {
let name = tokens.slice();
println!("{:?}", name);
if unwrap!(tokens) == Equal {
let temp_token = unwrap!(tokens);
if let Number(n) = temp_token {
tok = Some(Expr::GlobalDefinition(Rc::new(VarDefinition {name, value: n})));
}
}
}
}
tok
}
pub fn parse_value<'a>(token: &(Option<Result<Token, ()>>, &'a str)) -> Option<Expr<'a>> {
if let Some(Ok(tt)) = &token.0 {
let mut value = None;
if let Number(n) = tt {
value = Some(Expr::Number(*n));
} else if *tt == Identifier {
value = Some(Expr::Var(VarReference { name: token.1 }));
}
value
} else {
return None;
}
}
pub fn parse_fun_call(mut tokens: Lexer<Token>) -> Option<Expr> {
// Is it an Ident? → Is it a LeftParen? → Is it a value (I should really make a function to parse that) or is it a RightParen?
// ↓ ↓
// If it's a value, push that to `params`. Otherwise, params will just be a `Vec::new()`.
let mut tok = None;
if unwrap!(tokens) == Identifier {
let name = tokens.slice();
if unwrap!(tokens) == LeftParen {
let mut params = Vec::new();
while let Some(value) = parse_value!(tokens) {
params.push(Rc::new(value));
}
tok = Some(Expr::FunCall(FunCall {name, params: params.clone()}));
}
}
tok
}
pub fn match_operator(tokens: &mut Lexer<Token>) -> Option<MathOperator> {
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
}
}

View file