M kabel/Cargo.toml => kabel/Cargo.toml +3 -1
@@ 7,4 7,6 @@ edition = "2021"
[features]
timer = []
-debug = []
+debug = ["debug_lexer", "debug_parser"]
+debug_lexer = []
+debug_parser = []
A kabel/src/debug.rs => kabel/src/debug.rs +189 -0
@@ 0,0 1,189 @@
+use crate::{lexer::Token, parser::AST, push_output};
+
+pub fn debug_token_array(tokens: Vec<Token>) -> String {
+ let mut output = "".to_string();
+ for token in tokens {
+ output += &token.token_type.to_string();
+ output += "\n";
+ }
+ output[..output.len()-1].to_string()
+}
+pub fn debug_ast(ast: AST, level: usize) -> String {
+ use crate::parser::ASTType::*;
+ use crate::parser::BinOp::*;
+ use crate::parser::UnOp::*;
+ use crate::parser::Lit::*;
+ let mut output = "".to_string();
+ match ast.ast_type {
+ Program(asts) => {
+ output += &"| ".repeat(level);
+ output += "Program";
+ for ast in asts {
+ output += "\n";
+ output += &debug_ast(ast, level+1);
+ }
+ }
+ Function(name, args, block) => {
+ output += &"| ".repeat(level);
+ output += "Function ";
+ output += &(name.name + " ");
+ for arg in args {
+ output += &(arg.name + " ");
+ }
+ output += "\n";
+ output += &"| ".repeat(level);
+ output += &debug_ast(*block, level+1);
+ }
+ Return(expr) => {
+ output += &"| ".repeat(level);
+ output += "Return";
+ if let Some(expr) = *expr {
+ output += "\n";
+ output += &debug_ast(expr, level+1);
+ }
+ }
+ Loop(block) => {
+ output += &"| ".repeat(level);
+ output += "Loop";
+ output += "\n";
+ output += &debug_ast(*block, level+1);
+ }
+ While(condition, block) => {
+ output += &"| ".repeat(level);
+ output += "While";
+ output += "\n";
+ output += &debug_ast(*condition, level+1);
+ output += "\n";
+ output += &debug_ast(*block, level+1);
+ }
+ For(expr1, expr2, expr3, block) => {
+ output += &"| ".repeat(level);
+ output += "For";
+ if let Some(expr1) = *expr1 {
+ output += "\n";
+ output += &debug_ast(expr1, level+1);
+ }
+ if let Some(expr2) = *expr2 {
+ output += "\n";
+ output += &debug_ast(expr2, level+1);
+ }
+ if let Some(expr3) = *expr3 {
+ output += "\n";
+ output += &debug_ast(expr3, level+1);
+ }
+ output += "\n";
+ output += &debug_ast(*block, level+1);
+ }
+ Break => { output += "Break\n"; }
+ Continue => { output += "Continue\n"; }
+ If(condition, block, else_expr) => {
+ output += &"| ".repeat(level);
+ output += "If\n";
+ output += &debug_ast(*condition, level+1);
+ output += "\n";
+ output += &debug_ast(*block, level+1);
+ if let Some(else_expr) = *else_expr {
+ output += "\n";
+ output += &"| ".repeat(level);
+ output += "Else";
+ output += "\n";
+ output += &debug_ast(else_expr, level+1);
+ }
+ }
+ Block(asts) => {
+ output += &"| ".repeat(level);
+ output += "Block";
+ for ast in asts {
+ output += "\n";
+ output += &debug_ast(ast, level+1);
+ }
+ }
+ Decl(name, expr) => {
+ output += &"| ".repeat(level);
+ output += "Decl ";
+ output += &name.name;
+ output += "\n";
+ output += &debug_ast(*expr, level+1);
+ }
+ Assign(name, expr) => {
+ output += &"| ".repeat(level);
+ output += "Assign ";
+ output += &name.name;
+ output += "\n";
+ output += &debug_ast(*expr, level+1);
+ }
+ Ternary(condition, true_expr, false_expr) => {
+ output += &"| ".repeat(level);
+ output += "Ternary\n";
+ output += &debug_ast(*condition, level+1);
+ output += "\n";
+ output += &debug_ast(*true_expr, level+1);
+ output += "\n";
+ output += &debug_ast(*false_expr, level+1);
+ }
+ Subscript(array, index) => {
+ output += &"| ".repeat(level);
+ output += "Subscript\n";
+ output += &debug_ast(*array, level+1);
+ output += "\n";
+ output += &debug_ast(*index, level+1);
+ }
+ Binary(left, oper, right) => {
+ output += &"| ".repeat(level);
+ output += "Binary ";
+ push_output!(oper, output,
+ Add, Sub, Mul, Div, Mod, BitAnd, BitXor, BitOr,
+ Eq, Ne, Gr, Ge, Ls, Le, Or, And);
+ output += "\n";
+ output += &debug_ast(*left, level+1);
+ output += "\n";
+ output += &debug_ast(*right, level+1);
+ }
+ Unary(oper, right) => {
+ output += &"| ".repeat(level);
+ output += "Unary ";
+ push_output!(oper, output,
+ Not, Neg);
+ output += "\n";
+ output += &debug_ast(*right, level+1);
+ }
+ Lit(lit) => {
+ output += &"| ".repeat(level);
+ output += "Lit ";
+ match lit {
+ Ident(name) => {
+ output += &name;
+ }
+ Str(value) => {
+ output += &value;
+ }
+ Num(value) => {
+ output += &value.to_string();
+ }
+ Array(value) => {
+ for value in value {
+ output += "\n";
+ output += &debug_ast(value, level+1);
+ }
+ }
+ }
+ }
+ Call(name, args) => {
+ output += &"| ".repeat(level);
+ output += "Call ";
+ output += &name.name;
+ for arg in args {
+ output += "\n";
+ output += &debug_ast(arg, level+1);
+ }
+ }
+ Member(left, right) => {
+ output += &"| ".repeat(level);
+ output += "Member\n";
+ output += &debug_ast(*left, level+1);
+ output += "\n";
+ output += &debug_ast(*right, level+1);
+ }
+ }
+ output
+}
M kabel/src/lexer.rs => kabel/src/lexer.rs +33 -2
@@ 1,8 1,8 @@
-use std::collections::HashMap;
+use std::{collections::HashMap, fmt::Display};
use crate::{
error::{ErrorKind, KabelError},
- token,
+ token, token_display,
};
pub struct Lexer {
@@ 394,3 394,34 @@ pub enum TokenType {
Str(String),
Num(f32),
}
+
+impl Display for TokenType {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use TokenType::*;
+ token_display!(*self, f, Function, Return, Loop, While, For,
+ Break, Continue, If, Else, Var, Star, StarEqual,
+ Slash, SlashEqual, Percent, PercentEqual, Plus,
+ PlusPlus, PlusEqual, Minus, MinusMinus, MinusEqual,
+ LeftParen, RightParen, LeftBrace, RightBrace,
+ LeftSquare, RightSquare, Equal, EqualEqual,
+ Bang, BangEqual, Greater, GreaterEqual, Less,
+ LessEqual, And, AndEqual, AndAnd, Or, OrEqual, OrOr,
+ Caret, CaretEqual, Period, Comma, Semicolon, Colon, Question);
+ match *self {
+ Ident(ref name) => {
+ f.write_str("Ident ")?;
+ f.write_str(name)?;
+ }
+ Str(ref value) => {
+ f.write_str("Str ")?;
+ f.write_str(value)?;
+ }
+ Num(ref value) => {
+ f.write_str("Num ")?;
+ f.write_str(&value.to_string())?;
+ }
+ _ => {}
+ }
+ Ok(())
+ }
+}
M kabel/src/lib.rs => kabel/src/lib.rs +5 -1
@@ 1,10 1,12 @@
#[cfg(feature = "timer")]
use std::time::Instant;
+use debug::debug_token_array;
use lexer::{Lexer, Token};
use parser::{Parser, AST};
use semantic_analysis::Analyzer;
+pub mod debug;
pub mod error;
pub mod lexer;
pub mod macros;
@@ 50,7 52,9 @@ pub fn compile(program: String) -> String {
//println!("{}", error);
}
#[cfg(feature = "debug")]
- println!("{:?}", lexer.output);
+ {
+ output += &debug_token_array(lexer.output.clone());
+ }
if lexer.errors.len() != 0 || lexer.output.len() == 0 {
return output;
}
M kabel/src/macros.rs => kabel/src/macros.rs +19 -0
@@ 13,6 13,16 @@ macro_rules! token {
}
#[macro_export]
+macro_rules! token_display {
+ ( $match_to:expr, $f:expr, $( $name:tt),*) => {
+ match $match_to {
+ $( $name => { $f.write_str(stringify!($name))?; } ),*
+ _ => ()
+ }
+ }
+}
+
+#[macro_export]
macro_rules! lit {
($type:ident, $data:expr, $token:expr) => {
$crate::parser::AST {
@@ 54,6 64,15 @@ macro_rules! name {
}
#[macro_export]
+macro_rules! push_output {
+ ( $match_to:expr, $output:expr, $( $name:tt),*) => {
+ match $match_to {
+ $( $name => { $output += stringify!($name); } ),*
+ }
+ }
+}
+
+#[macro_export]
macro_rules! unexpected_token {
($self:expr, $message:expr, $token:expr) => {
$crate::error::KabelError::new(