Compare commits

..

No commits in common. "master" and "recursive" have entirely different histories.

19 changed files with 838 additions and 624 deletions

View file

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

24
LICENSE
View file

@ -1,24 +0,0 @@
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~ Normal file
View file

@ -0,0 +1,159 @@
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

66
src/#main.rs# Normal file
View file

@ -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()]));
}

View file

@ -1,256 +1,234 @@
use crate::parse::ast::*;
use skylang::temp;
use std::rc::Rc;
use skylang::temp;
#[derive(Debug)]
pub struct FasmCodegen;
#[macro_export]
macro_rules! fasm_codegen {
// Macro to make calling fasm_codegen function easier.
($exprs:expr) => {
fasm_codegen($exprs, true)
};
impl FasmCodegen {
pub fn new() -> Self {
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");
}
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());
}
}
// 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.
}
}
},
// 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 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 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");
// r10 ← r10 * r11; rax ← r10;
// The product will now be stored in the %rax register.
1 => {
// Second parameter. Put in %rsi.
unwrap!(p);
asm_start.push_str(format!("\tmov rsi, rax\n").as_str());
// rsi ← e.params[1];
},
// 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");
// r10 ← r10 - r11; rax ← r10;
// The difference 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 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.
3 => {
// Fourth parameter. Put in %rcx.
unwrap!(p);
asm_start.push_str(format!("\tmov rcx, rax\n").as_str());
// rcx ← e.params[3];
},
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 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];
},
// Call the function.
asm_start.push_str(format!("\tcall {}\n", e.name).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];
},
// 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());
},
2 => {
// Third parameter. Put in %rdx.
unwrap!(p);
asm_start.push_str("\tmov rdx, rax\n".to_string().as_str());
// rdx ← e.params[2];
},
// Breakpoint.
Expr::Breakpoint => {
// Write the interrupt for a debugger breakpoint.
asm_start.push_str("\tint3\n");
},
3 => {
// Fourth parameter. Put in %rcx.
unwrap!(p);
asm_start.push_str("\tmov rcx, rax\n".to_string().as_str());
// rcx ← e.params[3];
},
// 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
},
4 => {
// Fifth parameter. Put in %r8.
unwrap!(p);
asm_start.push_str("\tmov r8, rax".to_string().as_str());
// r8 ← e.params[4];
},
// 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");
},
5 => {
// Sixth parameter. Put in %r9.
unwrap!(p);
asm_start.push_str("\tmov r9, rax\n".to_string().as_str());
// r9 ← e.params[5];
},
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());
},
_ => {
// 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+)];
}
}
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());
}
}
// Call the function.
asm_start.push_str(format!("\tcall {}\n", e.name).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");
// 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);
},
}
},
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);
},
}
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
}
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
}

0
src/codegen/fasm.rs~ Normal file
View file

View file

@ -1,274 +0,0 @@
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,2 +1 @@
pub mod holeybytes;
pub mod fasm;

0
src/codegen/mod.rs~ Normal file
View file

1
src/lex/mod.rs~ Normal file
View file

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

149
src/lex/parse.rs~ Normal file
View file

@ -0,0 +1,149 @@
#![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,12 +1,11 @@
#![allow(unused)]
use std::string::String;
use logos::Logos;
use logos::Lexer;
use core::iter::Peekable;
pub use Token::*;
#[derive(Debug, Logos, PartialEq, Eq, Clone)]
#[derive(Debug, Logos, PartialEq, Eq)]
#[logos(skip r"[ \t\n\f]+")]
pub enum Token {
// SINGLE CHARACTER TOKENS
@ -85,11 +84,11 @@ pub enum Token {
// LITERALS
#[regex(r#"("[^"]*")|('[^']*')"#)]
StringLiteral, // A string literal.
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]^(^)^{^}^,^;^[+-/*%]]*"#, |lex| lex.slice().to_owned())]
Identifier(String), // An identifier.
Number(u64), // An integer.
#[regex(r#"[^[0-9]^"^-^[ \t\n\f]^\.^=^(^)^{^}.^,^;^[+-/*%]]+[^"^-^=^\..^[ \t\n\f]^(^)^{^}^,^;^[+-/*%]]*"#)]
Identifier, // An identifier.
#[token("true")]
True, // true
#[token("false")]
@ -107,51 +106,3 @@ 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"),
}
}
}

124
src/lex/tok.rs~ Normal file
View file

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

5
src/main.rs~ Normal file
View file

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

0
src/parse/ast.rs~ Normal file
View file

0
src/parse/mod.rs~ Normal file
View file

View file

@ -10,43 +10,92 @@ macro_rules! unwrap {
}
}
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);
}
#[macro_export]
macro_rules! parse_value {
($parse:expr) => {
parse_value(&($parse.next(), $parse.slice()))
}
}
pub fn parse_math(mut tokens: Lexer<Token>) -> Option<Expr> {
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)
}
// Is it a Value? → Is it an operator? → Is it a value?
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
};
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<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
}
}

0
src/parse/parse.rs~ Normal file
View file