Compare commits
No commits in common. "master" and "recursive" have entirely different histories.
|
@ -2,7 +2,6 @@
|
||||||
name = "skylang"
|
name = "skylang"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
channel = "nightly"
|
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
24
LICENSE
24
LICENSE
|
@ -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
159
TAGS~
Normal 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
66
src/#main.rs#
Normal 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()]));
|
||||||
|
}
|
|
@ -1,256 +1,234 @@
|
||||||
use crate::parse::ast::*;
|
use crate::parse::ast::*;
|
||||||
use skylang::temp;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use skylang::temp;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[macro_export]
|
||||||
pub struct FasmCodegen;
|
macro_rules! fasm_codegen {
|
||||||
|
// Macro to make calling fasm_codegen function easier.
|
||||||
|
($exprs:expr) => {
|
||||||
|
fasm_codegen($exprs, true)
|
||||||
|
};
|
||||||
|
|
||||||
impl FasmCodegen {
|
(fun: $exprs:expr) => {
|
||||||
pub fn new() -> Self {
|
fasm_codegen($exprs, false)
|
||||||
FasmCodegen
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pub fn fasm_codegen(&mut self, exprs: &Vec<Expr>, not_a_function: bool) -> String {
|
|
||||||
macro_rules! fasm_codegen {
|
pub fn fasm_codegen(exprs: &Vec<Expr>, not_a_function: bool) -> String {
|
||||||
// Macro to make calling fasm_codegen function easier.
|
// Define asm_func, used for functions.
|
||||||
($exprs:expr) => {{
|
let mut asm_func = String::new();
|
||||||
self.fasm_codegen($exprs, true)
|
// Define asm_data, used for variables.
|
||||||
}};
|
let mut asm_data = String::new();
|
||||||
|
// Define asm_start, used for the entry point.
|
||||||
(fun: $exprs:expr) => {{
|
let mut asm_start = String::new();
|
||||||
self.fasm_codegen($exprs, false)
|
macro_rules! unwrap {
|
||||||
}};
|
($item:expr) => {
|
||||||
}
|
asm_start.push_str(fasm_codegen!(fun: &vec![$item.as_ref().clone()]).as_str());
|
||||||
|
}
|
||||||
// Define asm_func, used for functions.
|
}
|
||||||
let mut asm_func = String::new();
|
|
||||||
// Define asm_data, used for variables.
|
|
||||||
let mut asm_data = String::new();
|
// If not_a_function, push necessary headers to the asm_start variable.
|
||||||
// Define asm_start, used for the entry point.
|
if not_a_function {
|
||||||
let mut asm_start = String::new();
|
asm_start.push_str("format ELF64 executable 3\n");
|
||||||
macro_rules! unwrap {
|
asm_start.push_str("segment readable executable\n");
|
||||||
($item:expr) => {
|
asm_start.push_str("entry _start\n");
|
||||||
asm_start.push_str(fasm_codegen!(fun: &vec![$item.as_ref().clone()]).as_str());
|
asm_start.push_str("_start:\n");
|
||||||
}
|
asm_data.push_str("\nsegment readable writable\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate over expressions.
|
||||||
// If not_a_function, push necessary headers to the asm_start variable.
|
for expr in exprs.iter() {
|
||||||
if not_a_function {
|
// Use patern matching on `expr`.
|
||||||
asm_start.push_str("format ELF64 executable 3\n");
|
match expr {
|
||||||
asm_start.push_str("segment readable executable\n");
|
// If the expression is a math expression.
|
||||||
asm_start.push_str("entry _start\n");
|
Expr::MathExpr(e) => {
|
||||||
asm_start.push_str("_start:\n");
|
unwrap!(e.left);
|
||||||
asm_data.push_str("\nsegment readable writable\n");
|
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());
|
||||||
// Iterate over expressions.
|
match e.operator {
|
||||||
for expr in exprs.iter() {
|
// If the operator is addition.
|
||||||
// Use patern matching on `expr`.
|
MathOperator::OP_ADD => {
|
||||||
match expr {
|
asm_start.push_str("\tadd r10, r11\n");
|
||||||
// If the expression is a math expression.
|
asm_start.push_str("\tmov rax, r10\n");
|
||||||
Expr::MathExpr(e) => {
|
// r10 ← r10 + r11; rax ← r10;
|
||||||
unwrap!(e.right);
|
// The sum will now be stored in the %rax register.
|
||||||
asm_start.push_str("\tpush rax\n");
|
},
|
||||||
unwrap!(e.left);
|
// If the operator is multiplication.
|
||||||
asm_start.push_str("\tpush rax\n");
|
MathOperator::OP_MULT => {
|
||||||
match e.operator {
|
asm_start.push_str("\timul r10, r11\n");
|
||||||
// If the operator is addition.
|
asm_start.push_str("\tmov rax, r10\n");
|
||||||
MathOperator::OP_ADD => {
|
// r10 ← r10 * r11; rax ← r10;
|
||||||
asm_start.push_str("\tpop r10\n");
|
// The product will now be stored in the %rax register.
|
||||||
asm_start.push_str("\tpop r11\n");
|
},
|
||||||
asm_start.push_str("\tadd r10, r11\n");
|
// If the operator is division.
|
||||||
asm_start.push_str("\tmov rax, r10\n");
|
MathOperator::OP_DIV => {
|
||||||
|
asm_start.push_str("\tmov rax, r10\n");
|
||||||
// r10 ← r10 + r11; rax ← r10;
|
asm_start.push_str("\txor rdx, rdx\n");
|
||||||
// The sum will now be stored in the %rax register.
|
asm_start.push_str("\tidiv r11\n");
|
||||||
},
|
// rax ← r10; rdx ← 0; rax ← concat(rax, rdx) / r11;
|
||||||
// If the operator is multiplication.
|
// The quotient will now be stored in the %rax register.
|
||||||
MathOperator::OP_MULT => {
|
},
|
||||||
asm_start.push_str("\tpop r10\n");
|
// If the operators is subtraction.
|
||||||
asm_start.push_str("\tpop r11\n");
|
MathOperator::OP_SUB => {
|
||||||
asm_start.push_str("\timul r10, r11\n");
|
asm_start.push_str("\tsub r10, r11\n");
|
||||||
asm_start.push_str("\tmov rax, r10\n");
|
asm_start.push_str("\tmov rax, r10\n");
|
||||||
|
// r10 ← r10 - r11; rax ← r10;
|
||||||
// r10 ← r10 * r11; rax ← r10;
|
// The difference will now be stored in the %rax register.
|
||||||
// The product will now be stored in the %rax register.
|
},
|
||||||
},
|
// If the operator is modulo.
|
||||||
// If the operator is division.
|
MathOperator::OP_MOD => {
|
||||||
MathOperator::OP_DIV => {
|
asm_start.push_str("\tmov rax, r10\n");
|
||||||
asm_start.push_str("\tpop r10\n");
|
asm_start.push_str("\txor rdx, rdx\n");
|
||||||
asm_start.push_str("\tpop r11\n");
|
asm_start.push_str("\tidiv r11\n");
|
||||||
asm_start.push_str("\tmov rax, r10\n");
|
asm_start.push_str("\tmov rax, rdx\n");
|
||||||
asm_start.push_str("\txor rdx, rdx\n");
|
// rax ← r10; rdx ← 0; rdx ← concat(rax, rdx) % r11; rax ← rdx;
|
||||||
asm_start.push_str("\tidiv r11\n");
|
// The remainder will now be stored in the %rax register.
|
||||||
// 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 => {
|
// If the expression is a function call.
|
||||||
asm_start.push_str("\tpop r10\n");
|
Expr::FunCall(e) => {
|
||||||
asm_start.push_str("\tpop r11\n");
|
for (i, p) in e.params.iter().enumerate() {
|
||||||
asm_start.push_str("\tsub r10, r11\n");
|
match i {
|
||||||
asm_start.push_str("\tmov rax, r10\n");
|
0 => {
|
||||||
|
// First parameter. Put in %rdi.
|
||||||
// r10 ← r10 - r11; rax ← r10;
|
unwrap!(p);
|
||||||
// The difference will now be stored in the %rax register.
|
asm_start.push_str(format!("\tmov rdi, rax\n").as_str());
|
||||||
},
|
// rdi ← e.params[0];
|
||||||
// If the operator is modulo.
|
},
|
||||||
MathOperator::OP_MOD => {
|
|
||||||
asm_start.push_str("\tpop r10\n");
|
1 => {
|
||||||
asm_start.push_str("\tpop r11\n");
|
// Second parameter. Put in %rsi.
|
||||||
asm_start.push_str("\tmov rax, r10\n");
|
unwrap!(p);
|
||||||
asm_start.push_str("\txor rdx, rdx\n");
|
asm_start.push_str(format!("\tmov rsi, rax\n").as_str());
|
||||||
asm_start.push_str("\tidiv r11\n");
|
// rsi ← e.params[1];
|
||||||
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.
|
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 expression is a function call.
|
},
|
||||||
Expr::FunCall(e) => {
|
|
||||||
for (i, p) in e.params.iter().enumerate() {
|
3 => {
|
||||||
match i {
|
// Fourth parameter. Put in %rcx.
|
||||||
0 => {
|
unwrap!(p);
|
||||||
// First parameter. Put in %rdi.
|
asm_start.push_str(format!("\tmov rcx, rax\n").as_str());
|
||||||
unwrap!(p);
|
// rcx ← e.params[3];
|
||||||
asm_start.push_str("\tmov rdi, rax\n".to_string().as_str());
|
},
|
||||||
// rdi ← e.params[0];
|
|
||||||
},
|
4 => {
|
||||||
|
// Fifth parameter. Put in %r8.
|
||||||
1 => {
|
unwrap!(p);
|
||||||
// Second parameter. Put in %rsi.
|
asm_start.push_str(format!("\tmov r8, rax").as_str());
|
||||||
unwrap!(p);
|
// r8 ← e.params[4];
|
||||||
asm_start.push_str("\tmov rsi, rax\n".to_string().as_str());
|
},
|
||||||
// rsi ← e.params[1];
|
|
||||||
},
|
5 => {
|
||||||
|
// Sixth parameter. Put in %r9.
|
||||||
2 => {
|
unwrap!(p);
|
||||||
// Third parameter. Put in %rdx.
|
asm_start.push_str(format!("\tmov r9, rax\n").as_str());
|
||||||
unwrap!(p);
|
// r9 ← e.params[5];
|
||||||
asm_start.push_str("\tmov rdx, rax\n".to_string().as_str());
|
},
|
||||||
// rdx ← e.params[2];
|
|
||||||
},
|
_ => {
|
||||||
|
// Parameters after the sixth parameter are pushed to the stack.
|
||||||
3 => {
|
unwrap!(p);
|
||||||
// Fourth parameter. Put in %rcx.
|
asm_start.push_str(format!("\tpush rax\n").as_str());
|
||||||
unwrap!(p);
|
// STACK_TOP ← e.params[(6+)];
|
||||||
asm_start.push_str("\tmov rcx, rax\n".to_string().as_str());
|
}
|
||||||
// rcx ← e.params[3];
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
4 => {
|
// Call the function.
|
||||||
// Fifth parameter. Put in %r8.
|
asm_start.push_str(format!("\tcall {}\n", e.name).as_str());
|
||||||
unwrap!(p);
|
},
|
||||||
asm_start.push_str("\tmov r8, rax".to_string().as_str());
|
|
||||||
// r8 ← e.params[4];
|
// Define a global variable.
|
||||||
},
|
Expr::GlobalDefinition(e) => {
|
||||||
|
// Define a 64-bit global variable.
|
||||||
5 => {
|
|
||||||
// Sixth parameter. Put in %r9.
|
asm_data.push_str(format!("\t{} dq {}", e.name, e.value).as_str());
|
||||||
unwrap!(p);
|
},
|
||||||
asm_start.push_str("\tmov r9, rax\n".to_string().as_str());
|
|
||||||
// r9 ← e.params[5];
|
// Breakpoint.
|
||||||
},
|
Expr::Breakpoint => {
|
||||||
|
// Write the interrupt for a debugger breakpoint.
|
||||||
_ => {
|
asm_start.push_str("\tint3\n");
|
||||||
// Parameters after the sixth parameter are pushed to the stack.
|
},
|
||||||
unwrap!(p);
|
|
||||||
asm_start.push_str("\tpush rax\n".to_string().as_str());
|
// Return something from a function.
|
||||||
// STACK_TOP ← e.params[(6+)];
|
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
|
||||||
// Call the function.
|
},
|
||||||
asm_start.push_str(format!("\tcall {}\n", e.name).as_str());
|
|
||||||
},
|
// A function defenition.
|
||||||
|
Expr::FunDefinition(e) => {
|
||||||
// Define a global variable.
|
// In x86-64 assembly, a function is defined as <function_name>:. Push this to the `asm_func`.
|
||||||
Expr::GlobalDefinition(e) => {
|
asm_func.push_str(format!("{}:\n", e.name).as_str());
|
||||||
// Define a 64-bit global variable.
|
// 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());
|
||||||
asm_data.push_str(format!("\t{} dq {}", e.name, e.value).as_str());
|
// Use the ret instruction to return from the procedure.
|
||||||
},
|
asm_func.push_str("\tret\n");
|
||||||
|
},
|
||||||
// Breakpoint.
|
|
||||||
Expr::Breakpoint => {
|
Expr::If(e) => {
|
||||||
// Write the interrupt for a debugger breakpoint.
|
// Increment the temporary variable/function counter.
|
||||||
asm_start.push_str("\tint3\n");
|
// Compare the left and right value.
|
||||||
},
|
unwrap!(e.left);
|
||||||
|
asm_start.push_str("mov rdi, rax");
|
||||||
// Return something from a function.
|
unwrap!(e.right);
|
||||||
Expr::Return(e) => {
|
asm_start.push_str("mov rsi, rax");
|
||||||
// Do the operation that should later be returned.
|
asm_start.push_str(format!("\tcmp rdi, rsi\n").as_str());
|
||||||
asm_start.push_str(fasm_codegen!(fun: &e).as_str());
|
// Check what the condition is.
|
||||||
// Move the return value to rbp + 8.
|
match e.cond {
|
||||||
// [rbp + 8] ← return_value
|
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());
|
||||||
// A function defenition.
|
},
|
||||||
Expr::FunDefinition(e) => {
|
|
||||||
// In x86-64 assembly, a function is defined as <function_name>:. Push this to the `asm_func`.
|
COND_OP::NE => {
|
||||||
asm_func.push_str(format!("{}:\n", e.name).as_str());
|
// If the compared values are not equal to eachother jump to the temporary function.
|
||||||
// Call the function itself specifying that you are defining a function, and push the returned value to `asm_func`.
|
asm_start.push_str(format!("jne .{}", temp!()).as_str());
|
||||||
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");
|
|
||||||
},
|
// Create the temporary function.
|
||||||
|
asm_func.push_str(format!(".{}:\n", temp!()).as_str());
|
||||||
Expr::If(e) => {
|
asm_func.push_str(fasm_codegen!(fun: &e.action).as_str());
|
||||||
// Increment the temporary variable/function counter.
|
asm_func.push_str("\tret\n");
|
||||||
// Compare the left and right value.
|
|
||||||
unwrap!(e.left);
|
},
|
||||||
asm_start.push_str("mov rdi, rax");
|
Expr::Number(n) => {
|
||||||
unwrap!(e.right);
|
asm_func.push_str(format!("\tmov rax, {}\n", n).as_str())
|
||||||
asm_start.push_str("mov rsi, rax");
|
},
|
||||||
asm_start.push_str("\tcmp rdi, rsi\n".to_string().as_str());
|
no => unsafe {
|
||||||
// Check what the condition is.
|
// Write some data I randomly typed to your memory because don't going around playing with something that I haven't implemented yet.
|
||||||
match e.cond {
|
println!("{:?} is not. implemented.", no);
|
||||||
COND_OP::EQ => {
|
let mut ptr = 0x00 as *mut f64;
|
||||||
// If the compared values are equal to each other jump to the temporary function.
|
::std::ptr::write(ptr, 124010240120401240.12410240124120401240);
|
||||||
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());
|
|
||||||
}
|
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");
|
||||||
// Create the temporary function.
|
asm_start.push_str("\txor rdi, rdi ; 0 is the exit code we want.\n");
|
||||||
asm_func.push_str(format!(".{}:\n", temp!()).as_str());
|
asm_start.push_str("\tsyscall ; this is the instruction to actually perform the system call.\n");
|
||||||
asm_func.push_str(fasm_codegen!(fun: &e.action).as_str());
|
}
|
||||||
asm_func.push_str("\tret\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.
|
||||||
Expr::Number(n) => {
|
|
||||||
asm_func.push_str(format!("\tmov rax, {}\n", n).as_str())
|
asm
|
||||||
},
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
// 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
0
src/codegen/fasm.rs~
Normal 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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,2 +1 @@
|
||||||
pub mod holeybytes;
|
|
||||||
pub mod fasm;
|
pub mod fasm;
|
||||||
|
|
0
src/codegen/mod.rs~
Normal file
0
src/codegen/mod.rs~
Normal file
1
src/lex/mod.rs~
Normal file
1
src/lex/mod.rs~
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod tok;
|
149
src/lex/parse.rs~
Normal file
149
src/lex/parse.rs~
Normal 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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,11 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
use std::string::String;
|
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
use logos::Lexer;
|
use logos::Lexer;
|
||||||
use core::iter::Peekable;
|
use core::iter::Peekable;
|
||||||
|
|
||||||
pub use Token::*;
|
pub use Token::*;
|
||||||
|
|
||||||
#[derive(Debug, Logos, PartialEq, Eq, Clone)]
|
#[derive(Debug, Logos, PartialEq, Eq)]
|
||||||
#[logos(skip r"[ \t\n\f]+")]
|
#[logos(skip r"[ \t\n\f]+")]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
// SINGLE CHARACTER TOKENS
|
// SINGLE CHARACTER TOKENS
|
||||||
|
@ -85,11 +84,11 @@ pub enum Token {
|
||||||
|
|
||||||
// LITERALS
|
// LITERALS
|
||||||
#[regex(r#"("[^"]*")|('[^']*')"#)]
|
#[regex(r#"("[^"]*")|('[^']*')"#)]
|
||||||
StringLiteral, // A string literal.
|
String, // A string literal.
|
||||||
#[regex("[0-9]+", |lex| lex.slice().parse().ok())]
|
#[regex("[0-9]+", |lex| lex.slice().parse().ok())]
|
||||||
Number(u64), // An integer.
|
Number(u64), // An integer.
|
||||||
#[regex(r#"[^[0-9]^"^-^[ \t\n\f]^\.^=^(^)^{^}.^,^;^[+-/*%]]+[^"^-^=^\..^[ \t\n\f]^(^)^{^}^,^;^[+-/*%]]*"#, |lex| lex.slice().to_owned())]
|
#[regex(r#"[^[0-9]^"^-^[ \t\n\f]^\.^=^(^)^{^}.^,^;^[+-/*%]]+[^"^-^=^\..^[ \t\n\f]^(^)^{^}^,^;^[+-/*%]]*"#)]
|
||||||
Identifier(String), // An identifier.
|
Identifier, // An identifier.
|
||||||
#[token("true")]
|
#[token("true")]
|
||||||
True, // true
|
True, // true
|
||||||
#[token("false")]
|
#[token("false")]
|
||||||
|
@ -107,51 +106,3 @@ pub fn lex_str(this: &str) -> Vec<(Token, &str)> {
|
||||||
|
|
||||||
buf
|
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
124
src/lex/tok.rs~
Normal 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: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
src/main.rs
52
src/main.rs
|
@ -1,12 +1,10 @@
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
#![feature(unsized_locals)]
|
|
||||||
#![feature(arc_unwrap_or_clone)]
|
|
||||||
#![feature(associated_type_bounds)]
|
|
||||||
pub mod lex;
|
pub mod lex;
|
||||||
pub mod codegen;
|
pub mod codegen;
|
||||||
use crate::codegen::fasm::*;
|
use crate::codegen::fasm::*;
|
||||||
use crate::lex::tok::*;
|
use crate::lex::tok::*;
|
||||||
|
use crate::parse::ast::*;
|
||||||
use crate::parse::parse::*;
|
use crate::parse::parse::*;
|
||||||
use logos::Logos;
|
use logos::Logos;
|
||||||
|
|
||||||
|
@ -19,17 +17,51 @@ macro_rules! arrow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut args = std::env::args();
|
// let fc = fasm_codegen!(
|
||||||
let (_, parsed) = (args.next(), args.next().unwrap());
|
// vec![
|
||||||
let mut lexer = Token::lexer(parsed.as_str());
|
// 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);
|
println!("\"{}\"", parsed);
|
||||||
arrow!(" ");
|
arrow!(" ");
|
||||||
println!("{:?}", lex_str(parsed.as_str()));
|
println!("{:?}", lex_str(parsed));
|
||||||
arrow!(" ");
|
arrow!(" ");
|
||||||
let parsed = parse_math(lexer);
|
let parsed = parse_math(lexer);
|
||||||
println!("{:?}", parsed);
|
println!("{:?}", parsed);
|
||||||
arrow!(" ");
|
arrow!(" ");
|
||||||
let mut code = FasmCodegen::new();
|
println!("{}", fasm_codegen!(&vec![parsed.unwrap()]));
|
||||||
println!("{}", code.fasm_codegen(&vec![parsed.unwrap()], true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
5
src/main.rs~
Normal file
5
src/main.rs~
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
pub mod lex;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("{:?}", lex::parse::match_identifier("goren-"));
|
||||||
|
}
|
0
src/parse/ast.rs~
Normal file
0
src/parse/ast.rs~
Normal file
0
src/parse/mod.rs~
Normal file
0
src/parse/mod.rs~
Normal file
|
@ -10,43 +10,92 @@ macro_rules! unwrap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expect_number(n: Option<Result<Token, ()>>) -> Expr<'static> {
|
#[macro_export]
|
||||||
match n {
|
macro_rules! parse_value {
|
||||||
Some(Ok(Number(res))) => Expr::Number(res),
|
($parse:expr) => {
|
||||||
Some(Ok(tok)) => {
|
parse_value(&($parse.next(), $parse.slice()))
|
||||||
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> {
|
pub fn parse_math(mut tokens: Lexer<Token>) -> Option<Expr> {
|
||||||
let mut left = expect_number(tokens.next());
|
// Is it a Value? → Is it an operator? → Is it a value?
|
||||||
|
|
||||||
loop {
|
if let Some(left) = parse_value!(tokens) {
|
||||||
let op = tokens.next();
|
if let Some(operator) = match_operator(&mut tokens) {
|
||||||
if !match_operator(&op).is_some() { break }
|
if let Some(right) = parse_value!(tokens) {
|
||||||
let right = expect_number(tokens.next());
|
let left = Rc::new(left);
|
||||||
left = Expr::MathExpr(Math {left: Rc::new(left), right: Rc::new(right), operator: match_operator(&op)?});
|
let right = Rc::new(right);
|
||||||
}
|
|
||||||
Some(left)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn match_operator(token: &Option<Result<Token, ()>>) -> Option<MathOperator> {
|
return Some(Expr::MathExpr(Math {left: left, right: right, operator}))
|
||||||
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
|
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
0
src/parse/parse.rs~
Normal file
Loading…
Reference in a new issue