aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock54
-rw-r--r--sloth/Cargo.toml1
-rw-r--r--sloth/src/main.rs2
-rw-r--r--sloth/src/parser/ast.rs27
-rw-r--r--sloth/src/parser/graph.rs197
-rw-r--r--sloth/src/parser/mod.rs4
-rw-r--r--sloth/src/parser/stmt.rs57
-rw-r--r--sloth/src/sloth_std.rs (renamed from sloth/src/std.rs)17
8 files changed, 264 insertions, 95 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 7f5d485..1d886a8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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}");
}