diff options
| -rw-r--r-- | Cargo.lock | 54 | ||||
| -rw-r--r-- | sloth/Cargo.toml | 1 | ||||
| -rw-r--r-- | sloth/src/main.rs | 2 | ||||
| -rw-r--r-- | sloth/src/parser/ast.rs | 27 | ||||
| -rw-r--r-- | sloth/src/parser/graph.rs | 197 | ||||
| -rw-r--r-- | sloth/src/parser/mod.rs | 4 | ||||
| -rw-r--r-- | sloth/src/parser/stmt.rs | 57 | ||||
| -rw-r--r-- | sloth/src/sloth_std.rs (renamed from sloth/src/std.rs) | 17 |
8 files changed, 264 insertions, 95 deletions
@@ -42,6 +42,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" [[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] name = "inkwell" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -146,6 +157,12 @@ dependencies = [ ] [[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] name = "proc-macro2" version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -164,6 +181,36 @@ dependencies = [ ] [[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] name = "redox_syscall" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -207,6 +254,7 @@ version = "0.1.0" dependencies = [ "inkwell", "itertools", + "rand", "thiserror", ] @@ -254,6 +302,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] name = "windows-targets" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/sloth/Cargo.toml b/sloth/Cargo.toml index 4fabdb7..1146e8e 100644 --- a/sloth/Cargo.toml +++ b/sloth/Cargo.toml @@ -8,4 +8,5 @@ edition.workspace = true [dependencies] inkwell = { version = "0.2.0", features = ["llvm15-0"] } itertools = "0.10.5" +rand = "0.8.5" thiserror = "1.0.40" diff --git a/sloth/src/main.rs b/sloth/src/main.rs index 67f8f97..0cfeb09 100644 --- a/sloth/src/main.rs +++ b/sloth/src/main.rs @@ -10,11 +10,11 @@ pub mod codegen; pub mod compiler; pub mod lexer; pub mod parser; +pub mod sloth_std; pub mod symbol; use std::{env, fs}; -use compiler::Compiler; use itertools::Itertools; use lexer::Lexer; use parser::graph::GraphBuilder; diff --git a/sloth/src/parser/ast.rs b/sloth/src/parser/ast.rs index 2c70156..749271c 100644 --- a/sloth/src/parser/ast.rs +++ b/sloth/src/parser/ast.rs @@ -1,3 +1,5 @@ +use std::fmt::{format, Display}; + use crate::lexer::{self, TokenType}; use crate::parser::ParsingError; @@ -49,16 +51,16 @@ impl Stmt { // TODO: Values & Constants #[derive(PartialEq, Clone, Debug)] pub enum StmtKind { - Block(Vec<StmtKind>), + Block(Vec<Stmt>), ExprStmt(Expr), IfStmt { condition: Expr, - if_then: Box<StmtKind>, - else_then: Option<Box<StmtKind>>, + if_then: Box<Stmt>, + else_then: Option<Box<Stmt>>, }, WhileStmt { condition: Expr, - body: Box<StmtKind>, + body: Box<Stmt>, }, DefineVariable { identifier: String, @@ -76,7 +78,7 @@ pub enum StmtKind { identifier: String, inputs: Vec<FunctionInput>, output: Option<String>, - body: Box<StmtKind>, + body: Box<Stmt>, }, Return(Expr), } @@ -117,6 +119,21 @@ impl From<Literal> for ExprKind { } } +impl Display for Literal { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let value = match self { + Literal::Integer(i) => format!("{i}"), + Literal::Float(f) => format!("{f}"), + Literal::Boolean(b) => format!("{b}"), + Literal::Character(c) => format!("'{c}'"), + Literal::String(s) => format!("\"{s}\""), + Literal::Array(a) => format!("<Array>"), + }; + + write!(f, "{value}") + } +} + #[derive(Debug, Clone, Copy, PartialEq)] pub enum BinaryOp { Add, diff --git a/sloth/src/parser/graph.rs b/sloth/src/parser/graph.rs index b2a9324..e8236be 100644 --- a/sloth/src/parser/graph.rs +++ b/sloth/src/parser/graph.rs @@ -1,16 +1,14 @@ use std::fmt::{Error, Write}; -use super::ast::{ExprKind, StmtKind}; +use super::ast::{Expr, ExprKind, Stmt, StmtKind}; pub struct GraphBuilder { - i: i32, graph: String, } impl GraphBuilder { - pub fn generate(ast: &[StmtKind]) -> Result<String, Error> { + pub fn generate(ast: &[Stmt]) -> Result<String, Error> { let mut this = Self { - i: 0, graph: String::new(), }; @@ -18,7 +16,6 @@ impl GraphBuilder { for stmt in ast.iter() { this.traverse_stmt0(stmt)?; } - this.i = 0; for stmt in ast.iter() { this.traverse_stmt(stmt)?; } @@ -27,12 +24,10 @@ impl GraphBuilder { Ok(this.graph) } - fn traverse_stmt0(&mut self, stmt: &StmtKind) -> Result<(), Error> { - self.i += 1; - - match stmt { + fn traverse_stmt0(&mut self, stmt: &Stmt) -> Result<(), Error> { + match &stmt.kind { StmtKind::Block(body) => { - writeln!(&mut self.graph, "N{} [shape=box label=\"Block\"];", self.i)?; + writeln!(&mut self.graph, "N{} [shape=box label=\"Block\"];", stmt.id)?; for stmt in body.iter() { self.traverse_stmt0(stmt)?; } @@ -41,17 +36,21 @@ impl GraphBuilder { writeln!( &mut self.graph, "N{} [shape=box label=\"ExprStmt\"];", - self.i + stmt.id, )?; - // self.traverse_expr0(expr); + self.traverse_expr0(expr)?; } StmtKind::IfStmt { condition, if_then, else_then, } => { - writeln!(&mut self.graph, "N{} [shape=box label=\"IfStmt\"];", self.i)?; - // self.traverse_expr0(condition); + writeln!( + &mut self.graph, + "N{} [shape=box label=\"IfStmt\"];", + stmt.id + )?; + self.traverse_expr0(condition)?; self.traverse_stmt0(if_then)?; if let Some(else_then) = else_then { self.traverse_stmt0(else_then)?; @@ -61,9 +60,9 @@ impl GraphBuilder { writeln!( &mut self.graph, "N{} [shape=box label=\"WhileStmt\"];", - self.i + stmt.id )?; - // self.traverse_expr0(condition); + self.traverse_expr0(condition)?; self.traverse_stmt0(body)?; } StmtKind::DefineVariable { @@ -74,17 +73,17 @@ impl GraphBuilder { writeln!( &mut self.graph, "N{} [shape=box label=\"DefineVariable\\n\\nIdentifier={}\\nType={}\"];", - self.i, identifier, typ + stmt.id, identifier, typ )?; - // self.traverse_expr0(value); + self.traverse_expr0(value)?; } StmtKind::AssignVariable { identifier, value } => { writeln!( &mut self.graph, "N{} [shape=box label=\"AssignVariable\\n\\nIdentifier={}\"];", - self.i, identifier + stmt.id, identifier )?; - // self.traverse_expr0(value); + self.traverse_expr0(value)?; } StmtKind::DefineFunction { identifier, @@ -96,7 +95,7 @@ impl GraphBuilder { &mut self.graph, "N{} [shape=box \ label=\"DefineFunction\\n\\nIdentifier={}\\nInputs={}\\nOutput={}\"];", - self.i, + stmt.id, identifier, inputs.len(), output.is_some() @@ -104,57 +103,137 @@ impl GraphBuilder { self.traverse_stmt0(body)?; } StmtKind::Return(expr) => { - writeln!(&mut self.graph, "N{} [shape=box label=\"Return\"];", self.i)?; - // self.traverse_expr0(expr); + writeln!( + &mut self.graph, + "N{} [shape=box label=\"Return\"];", + stmt.id + )?; + self.traverse_expr0(expr)?; } } Ok(()) } - fn traverse_expr0(&mut self, expr: &ExprKind) { - self.i += 1; - // match expr { - // Expr::Grouping(_) => todo!(), - // Expr::Literal(_) => todo!(), - // Expr::Identifier(_) => todo!(), - // Expr::BinaryOp { op, lhs, rhs } => todo!(), - // Expr::UnaryOp { op, value } => todo!(), - // Expr::Call { callee, args } => todo!(), - // } - } + fn traverse_expr0(&mut self, expr: &Expr) -> Result<(), Error> { + match &expr.kind { + ExprKind::Grouping(child) => { + writeln!( + &mut self.graph, + "N{} [shape=diamond label=\"Grouping\"];", + expr.id + )?; + self.traverse_expr0(child)?; + } + ExprKind::Literal(literal) => { + writeln!( + &mut self.graph, + "N{} [shape=diamond label=\"Literal\\n\\nValue={}\"];", + expr.id, literal + )?; + } + ExprKind::Identifier(identifier) => { + writeln!( + &mut self.graph, + "N{} [shape=diamond label=\"Identifier\\n\\nIdentifier={}\"];", + expr.id, identifier + )?; + } + ExprKind::BinaryOp { op, lhs, rhs } => { + self.traverse_expr0(lhs)?; + self.traverse_expr0(rhs)?; + } + ExprKind::UnaryOp { op, value } => { + self.traverse_expr0(value)?; + } + ExprKind::Call { callee, args } => (), + } - fn traverse_stmt(&mut self, stmt: &StmtKind) -> Result<(), Error> { - self.i += 1; + Ok(()) + } - match stmt { - StmtKind::Block(_) => todo!(), - StmtKind::ExprStmt(_) => todo!(), + fn traverse_stmt(&mut self, stmt: &Stmt) -> Result<(), Error> { + match &stmt.kind { + StmtKind::Block(children) => { + for child in children { + writeln!(&mut self.graph, "N{} -> N{};", stmt.id, child.id)?; + self.traverse_stmt(child)?; + } + } + StmtKind::ExprStmt(expr) => { + writeln!(&mut self.graph, "N{} -> N{};", stmt.id, expr.id)?; + self.traverse_expr(expr)?; + } StmtKind::IfStmt { - condition, - if_then, - else_then, - } => todo!(), - StmtKind::WhileStmt { condition, body } => todo!(), - StmtKind::DefineVariable { - identifier, - value, - typ, - } => todo!(), - StmtKind::AssignVariable { identifier, value } => todo!(), - StmtKind::DefineFunction { - identifier, - inputs, - output, - body, - } => todo!(), - StmtKind::Return(_) => todo!(), + if_then, else_then, .. + } => { + writeln!( + &mut self.graph, + "N{} -> N{} [label = \"If Then\"];", + stmt.id, if_then.id + )?; + self.traverse_stmt(if_then)?; + if let Some(else_then) = else_then { + writeln!( + &mut self.graph, + "N{} -> N{} [label = \"Else Then\"];", + stmt.id, else_then.id + )?; + self.traverse_stmt(else_then)?; + } + } + StmtKind::WhileStmt { condition, body } => { + writeln!( + &mut self.graph, + "N{} -> N{} [label = \"Condition\"];", + stmt.id, condition.id + )?; + writeln!( + &mut self.graph, + "N{} -> N{} [label = \"Body\"];", + stmt.id, body.id + )?; + self.traverse_expr(condition)?; + self.traverse_stmt(body)?; + } + StmtKind::DefineVariable { value, .. } => { + writeln!(&mut self.graph, "N{} -> N{};", stmt.id, value.id)?; + self.traverse_expr(value)?; + } + StmtKind::AssignVariable { value, .. } => { + writeln!(&mut self.graph, "N{} -> N{};", stmt.id, value.id)?; + self.traverse_expr(value)?; + } + StmtKind::DefineFunction { body, .. } => { + writeln!( + &mut self.graph, + "N{} -> N{} [label = \"Body\"];", + stmt.id, body.id + )?; + self.traverse_stmt(body)?; + } + StmtKind::Return(_) => (), } Ok(()) } - fn traverse_expr(&mut self, expr: &ExprKind) { - // + fn traverse_expr(&mut self, expr: &Expr) -> Result<(), Error> { + match &expr.kind { + ExprKind::Grouping(children) => { + writeln!(&mut self.graph, "N{} -> N{};", expr.id, children.id)?; + } + ExprKind::BinaryOp { lhs, rhs, .. } => { + writeln!(&mut self.graph, "N{} -> N{};", expr.id, lhs.id)?; + writeln!(&mut self.graph, "N{} -> N{};", expr.id, rhs.id)?; + } + ExprKind::UnaryOp { value, .. } => { + writeln!(&mut self.graph, "N{} -> N{};", expr.id, value.id)?; + } + ExprKind::Call { callee, args } => (), + _ => (), + } + + Ok(()) } } diff --git a/sloth/src/parser/mod.rs b/sloth/src/parser/mod.rs index 958166a..bc47ddd 100644 --- a/sloth/src/parser/mod.rs +++ b/sloth/src/parser/mod.rs @@ -3,7 +3,7 @@ pub mod expr; pub mod graph; pub mod stmt; -use self::ast::{Literal, StmtKind}; +use self::ast::{Literal, Stmt}; use crate::lexer::{Token, TokenType}; #[derive(thiserror::Error, Debug, PartialEq)] @@ -22,7 +22,7 @@ pub struct AstParser<'a> { } impl<'a> AstParser<'a> { - pub fn parse(tokens: Vec<Token<'a>>) -> Result<Vec<StmtKind>, ParsingError> { + pub fn parse(tokens: Vec<Token<'a>>) -> Result<Vec<Stmt>, ParsingError> { let mut parser = Self::new(tokens); let mut statements = Vec::new(); diff --git a/sloth/src/parser/stmt.rs b/sloth/src/parser/stmt.rs index f9980e3..c8913b4 100644 --- a/sloth/src/parser/stmt.rs +++ b/sloth/src/parser/stmt.rs @@ -1,9 +1,9 @@ -use super::ast::{FunctionInput, StmtKind}; +use super::ast::{FunctionInput, Stmt, StmtKind}; use super::{AstParser, ParsingError}; use crate::lexer::TokenType; impl<'a> AstParser<'a> { - pub(super) fn statement(&mut self) -> Result<StmtKind, ParsingError> { + pub(super) fn statement(&mut self) -> Result<Stmt, ParsingError> { match self.peek().tt { TokenType::OpeningBrace => self.block(), @@ -18,7 +18,7 @@ impl<'a> AstParser<'a> { } } - fn if_stmt(&mut self) -> Result<StmtKind, ParsingError> { + fn if_stmt(&mut self) -> Result<Stmt, ParsingError> { // Consume the if token self.consume(TokenType::If, "Expected if")?; @@ -36,28 +36,32 @@ impl<'a> AstParser<'a> { } } - Ok(StmtKind::IfStmt { + let kind = StmtKind::IfStmt { condition, if_then: if_then.into(), else_then: else_then.map(|it| it.into()), - }) + }; + + Ok(Stmt::new(self.reserve_id(), kind)) } - fn while_stmt(&mut self) -> Result<StmtKind, ParsingError> { + fn while_stmt(&mut self) -> Result<Stmt, ParsingError> { // Consume the while token self.consume(TokenType::While, "Expected while")?; let condition = self.expression()?; let body = self.block()?; - Ok(StmtKind::WhileStmt { + let kind = StmtKind::WhileStmt { condition, body: body.into(), - }) + }; + + Ok(Stmt::new(self.reserve_id(), kind)) } // TODO: Make variable types optional - fn define_variable(&mut self) -> Result<StmtKind, ParsingError> { + fn define_variable(&mut self) -> Result<Stmt, ParsingError> { // Consume the var token self.consume(TokenType::Var, "Expected var")?; @@ -72,15 +76,17 @@ impl<'a> AstParser<'a> { self.consume(TokenType::SemiColon, "Expected ';' at end of statement")?; - Ok(StmtKind::DefineVariable { + let kind = StmtKind::DefineVariable { identifier, value, typ, - }) + }; + + Ok(Stmt::new(self.reserve_id(), kind)) } // TODO: Make argument types optional - fn define_function(&mut self) -> Result<StmtKind, ParsingError> { + fn define_function(&mut self) -> Result<Stmt, ParsingError> { // Consume the fn token self.consume(TokenType::Fn, "Expected fn")?; @@ -113,36 +119,41 @@ impl<'a> AstParser<'a> { // Get the function body let body = self.block()?; - Ok(StmtKind::DefineFunction { + let kind = StmtKind::DefineFunction { identifier, inputs, output, body: body.into(), - }) + }; + + Ok(Stmt::new(self.reserve_id(), kind)) } - fn return_stmt(&mut self) -> Result<StmtKind, ParsingError> { + fn return_stmt(&mut self) -> Result<Stmt, ParsingError> { self.consume(TokenType::Return, "Expected return")?; let value = self.expression()?; self.consume(TokenType::SemiColon, "Expected ';' at end of statement")?; - Ok(StmtKind::Return(value)) + let kind = StmtKind::Return(value); + Ok(Stmt::new(self.reserve_id(), kind)) } - fn assign_variable(&mut self) -> Result<StmtKind, ParsingError> { + fn assign_variable(&mut self) -> Result<Stmt, ParsingError> { let identifier = self.consume_identifier()?; self.consume(TokenType::Eq, "Expected '='")?; let value = self.expression()?; self.consume(TokenType::SemiColon, "Expected ';' at end of statement")?; - Ok(StmtKind::AssignVariable { identifier, value }) + let kind = StmtKind::AssignVariable { identifier, value }; + Ok(Stmt::new(self.reserve_id(), kind)) } - fn expression_stmt(&mut self) -> Result<StmtKind, ParsingError> { + fn expression_stmt(&mut self) -> Result<Stmt, ParsingError> { let expr = self.expression()?; self.consume(TokenType::SemiColon, "Expected ';' at end of statement")?; - Ok(StmtKind::ExprStmt(expr)) + let kind = StmtKind::ExprStmt(expr); + Ok(Stmt::new(self.reserve_id(), kind)) } - fn block(&mut self) -> Result<StmtKind, ParsingError> { + fn block(&mut self) -> Result<Stmt, ParsingError> { // Consume the opening brace self.consume(TokenType::OpeningBrace, "Expected '{'")?; @@ -155,7 +166,9 @@ impl<'a> AstParser<'a> { // Consume the closing brace self.consume(TokenType::ClosingBrace, "Expected '}'")?; - Ok(StmtKind::Block(body)) + let kind = StmtKind::Block(body); + + Ok(Stmt::new(self.reserve_id(), kind)) } } diff --git a/sloth/src/std.rs b/sloth/src/sloth_std.rs index cae9aaa..7e10297 100644 --- a/sloth/src/std.rs +++ b/sloth/src/sloth_std.rs @@ -1,21 +1,26 @@ -use rand::Rng; +use std::ffi::{c_char, CStr}; -use std::ffi::CString; +use rand::Rng; #[no_mangle] pub extern "C" fn rand(a: i64, b: i64) -> i64 { - let value = rand::thread_rng().gen_range(a..b); - return value; + rand::thread_rng().gen_range(a..b) } #[no_mangle] +/// # Safety +/// +/// Function is unsafe if passed pointer is not a valid CStr pub unsafe extern "C" fn println(s: *const c_char) { let s = unsafe { CStr::from_ptr(s) }.to_str().unwrap(); - println("{s}"); + println!("{s}"); } #[no_mangle] +/// # Safety +/// +/// Function is unsafe if passed pointer is not a valid CStr pub unsafe extern "C" fn print(s: *const c_char) { let s = unsafe { CStr::from_ptr(s) }.to_str().unwrap(); - print("{s}"); + print!("{s}"); } |
