aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCody <cody@codyq.dev>2023-06-24 21:11:44 -0500
committerCody <cody@codyq.dev>2023-06-24 21:11:44 -0500
commitdef8adfcb9a9572f4e030990626a0d08377118bd (patch)
treef230fdf3d281f3f9a91f0510d954344f2bdb48ce
parent0ee365c80667a3a5f43a86ead75fd0da5be23282 (diff)
downloadsloth-def8adfcb9a9572f4e030990626a0d08377118bd.tar.gz
hehehaha
-rw-r--r--examples/guessing.sloth47
-rw-r--r--examples/hello.sloth2
-rw-r--r--graph.pngbin0 -> 350220 bytes
-rw-r--r--sloth/src/analysis/mod.rs25
-rw-r--r--sloth/src/analysis/setup.rs77
-rw-r--r--sloth/src/lexer.rs3
-rw-r--r--sloth/src/main.rs20
-rw-r--r--sloth/src/parser/ast.rs32
-rw-r--r--sloth/src/parser/graph.rs96
-rw-r--r--sloth/src/parser/stmt.rs145
-rw-r--r--sloth/src/symtable.rs45
11 files changed, 337 insertions, 155 deletions
diff --git a/examples/guessing.sloth b/examples/guessing.sloth
index 05c25db..5a759e5 100644
--- a/examples/guessing.sloth
+++ b/examples/guessing.sloth
@@ -1,26 +1,29 @@
-val computer: int = random(1, 10);
+foreign fn print();
+foreign fn println();
+foreign fn readln() String;
+foreign fn random(min: Int, max: Int) Int;
+foreign fn parse_int(str: String) Int;
-var tries: int = 0;
-var correct: bool = false;
+fn main() {
+ var computer: Int = random(1, 10);
+ var tries: Int = 0;
+ var correct: Bool = false;
-while !correct {
- print("\nPick a number between 1 and 10: ");
- val human: int = parse_int(readln());
+ while !correct {
+ print("Pick a number between 1 and 10: ");
+ var human: Int = parse_int(readln());
- if human == computer {
- println("You guessed the same number as me!");
- correct = true;
- }
-
- if human > computer {
- println("Your guess was too high.");
- }
-
- if human < computer {
- println("Your guess was too low.");
- }
-
- tries = tries + 1;
-}
+ if human == computer {
+ println("You guessed the same number as me!\n");
+ correct = true;
+ } else if human > computer {
+ println("Your guess was too high.\n");
+ } else if human < computer {
+ println("Your guess was too low.\n");
+ }
+
+ tries = tries + 1;
+ }
-println("\nIt took you ", tries, " tries to guess correctly!");
+ println("It took you ", tries, " tries to guess correctly!");
+}
diff --git a/examples/hello.sloth b/examples/hello.sloth
index 8b395e8..a955e66 100644
--- a/examples/hello.sloth
+++ b/examples/hello.sloth
@@ -1,3 +1,5 @@
+foreign fn example(arg: Int) Void;
+
fn main() {
var i: Int = 10;
var j: Int = 1.0 - 1;
diff --git a/graph.png b/graph.png
new file mode 100644
index 0000000..f7c192d
--- /dev/null
+++ b/graph.png
Binary files differ
diff --git a/sloth/src/analysis/mod.rs b/sloth/src/analysis/mod.rs
index 857fbb8..8232e0e 100644
--- a/sloth/src/analysis/mod.rs
+++ b/sloth/src/analysis/mod.rs
@@ -1,5 +1,6 @@
+pub mod setup;
+
use crate::parser::ast::{AstNode, ExprKind, Stmt, StmtKind};
-use crate::symtable::{Symbol, SymbolType};
#[derive(Debug, thiserror::Error)]
pub enum AnalysisError {
@@ -22,32 +23,12 @@ impl AnalysisError {
}
pub fn analyze(root: &mut Stmt) -> Result<(), AnalysisError> {
- populate_symtable(&root.as_node());
+ setup::populate_symtable(&root.as_node())?;
check_usage(&root.as_node())?;
Ok(())
}
-fn populate_symtable(node: &AstNode) {
- if let AstNode::Stmt(stmt) = node {
- match &stmt.kind {
- StmtKind::DefineVariable { identifier, .. } => {
- let mut table = stmt.symtable.clone();
- table.insert(identifier.to_owned(), Symbol::new(SymbolType::Variable));
- }
- StmtKind::DefineFunction { identifier, .. } => {
- let mut table = stmt.symtable.clone();
- table.insert(identifier.to_owned(), Symbol::new(SymbolType::Function));
- }
- _ => (),
- }
- }
-
- for child in node.children() {
- populate_symtable(&child);
- }
-}
-
fn check_usage(node: &AstNode) -> Result<(), AnalysisError> {
if let AstNode::Expr(expr) = node && let ExprKind::Identifier(identifier) = &expr.kind && !expr.symtable.clone().contains(identifier) {
return Err(AnalysisError::UnknownIdentifier(expr.line, identifier.clone()));
diff --git a/sloth/src/analysis/setup.rs b/sloth/src/analysis/setup.rs
new file mode 100644
index 0000000..0c4f228
--- /dev/null
+++ b/sloth/src/analysis/setup.rs
@@ -0,0 +1,77 @@
+use super::AnalysisError;
+use crate::parser::ast::{AstNode, Function, FunctionInput, FunctionKind, StmtKind};
+use crate::symtable::{Symbol, SymbolTable, Type};
+
+pub(super) fn populate_symtable(node: &AstNode) -> Result<(), AnalysisError> {
+ if let AstNode::Stmt(stmt) = node {
+ let mut table = stmt.symtable.clone();
+
+ match &stmt.kind {
+ StmtKind::DefineVariable {
+ identifier, typ, ..
+ } => {
+ // When a variable is defined add it to the symbol table of the current scope.
+ let symbol = build_value_symbol(&table, typ)?;
+ table.insert(identifier.to_owned(), symbol);
+ }
+ StmtKind::DefineFunction(Function {
+ identifier,
+ inputs,
+ output,
+ kind,
+ }) => {
+ // When a function is defined add the function to the symbol
+ // table of the current scope, and add the inputs to the child
+ // (body) scope.
+ let function_symbol = build_function_symbol(&table, inputs, output.as_deref())?;
+ table.insert(identifier.to_owned(), function_symbol);
+
+ if let FunctionKind::Normal { body } = kind {
+ let mut body_table = body.symtable.clone();
+
+ for input in inputs {
+ let symbol = build_value_symbol(&body_table, &input.typ)?;
+ body_table.insert(input.identifier.to_owned(), symbol);
+ }
+ }
+ }
+ _ => (),
+ }
+ }
+
+ for child in node.children() {
+ populate_symtable(&child)?;
+ }
+
+ Ok(())
+}
+
+fn build_value_symbol(table: &SymbolTable, typ: &str) -> Result<Symbol, AnalysisError> {
+ let typ = table
+ .get_type(typ)
+ .ok_or(AnalysisError::UnknownIdentifier(0, typ.to_owned()))?;
+
+ Ok(Symbol::Value(typ))
+}
+
+fn build_function_symbol(
+ table: &SymbolTable,
+ inputs: &[FunctionInput],
+ output: Option<&str>,
+) -> Result<Symbol, AnalysisError> {
+ let inputs = inputs
+ .iter()
+ .map(|it| table.get_type(&it.typ))
+ .collect::<Option<Vec<_>>>()
+ .ok_or(AnalysisError::UnknownIdentifier(0, "0xOwO".to_owned()))?;
+
+ let output = output
+ .map(|it| table.get_type(it))
+ .unwrap_or(Some(Type::Void))
+ .ok_or(AnalysisError::UnknownIdentifier(0, "0xUwU".to_owned()))?;
+
+ Ok(Symbol::Value(Type::Function {
+ inputs,
+ output: output.into(),
+ }))
+}
diff --git a/sloth/src/lexer.rs b/sloth/src/lexer.rs
index 3ad39a2..128b012 100644
--- a/sloth/src/lexer.rs
+++ b/sloth/src/lexer.rs
@@ -102,6 +102,8 @@ pub enum TokenType {
As,
+ Foreign,
+
// Other
Literal(Literal),
Identifier(String),
@@ -406,6 +408,7 @@ impl<'a> Iterator for Lexer<'a> {
"break" => TokenType::Break,
"continue" => TokenType::Continue,
"as" => TokenType::As,
+ "foreign" => TokenType::Foreign,
"true" => Literal::Boolean(true).into(),
"false" => Literal::Boolean(false).into(),
_ => TokenType::Identifier(value),
diff --git a/sloth/src/main.rs b/sloth/src/main.rs
index 1eb0ead..ec9eb7e 100644
--- a/sloth/src/main.rs
+++ b/sloth/src/main.rs
@@ -15,11 +15,14 @@ pub mod symtable;
use std::{env, fs};
-use analysis::analyze;
use itertools::Itertools;
use lexer::Lexer;
use parser::AstParser;
-use symtable::{Symbol, SymbolTable, SymbolType};
+use symtable::{Symbol, SymbolTable};
+
+use crate::analysis::analyze;
+use crate::parser::graph::GraphBuilder;
+use crate::symtable::Type;
fn main() {
let args = env::args().collect_vec();
@@ -38,9 +41,10 @@ fn main() {
// Symbol table
let mut global_symtable = SymbolTable::new();
- global_symtable.insert("print".to_owned(), Symbol::new(SymbolType::Function));
- global_symtable.insert("println".to_owned(), Symbol::new(SymbolType::Function));
- global_symtable.insert("readln".to_owned(), Symbol::new(SymbolType::Function));
+ global_symtable.insert("Void".into(), Symbol::Type(Type::Void));
+ global_symtable.insert("Int".into(), Symbol::Type(Type::Integer));
+ global_symtable.insert("Float".into(), Symbol::Type(Type::Float));
+ global_symtable.insert("Bool".into(), Symbol::Type(Type::Boolean));
// Parsing
let tokens = Lexer::new(&source).collect_vec();
@@ -51,8 +55,10 @@ fn main() {
return;
}
- println!("{ast:#?}");
+ println!("Suces");
+
+ // println!("{ast:#?}");
- // let graph = GraphBuilder::generate(&ast).unwrap();
+ // let graph = GraphBuilder::generate(Some(&source), &ast).unwrap();
// println!("{graph}");
}
diff --git a/sloth/src/parser/ast.rs b/sloth/src/parser/ast.rs
index a542847..8b58fcd 100644
--- a/sloth/src/parser/ast.rs
+++ b/sloth/src/parser/ast.rs
@@ -172,7 +172,11 @@ impl Stmt {
}
StmtKind::DefineVariable { value, .. } => children.push(value.as_node()),
StmtKind::AssignVariable { value, .. } => children.push(value.as_node()),
- StmtKind::DefineFunction { body, .. } => children.push(body.as_node()),
+ StmtKind::DefineFunction(Function { kind, .. }) => {
+ if let FunctionKind::Normal { body } = kind {
+ children.push(body.as_node())
+ }
+ }
StmtKind::Return(value) => children.push(value.as_node()),
}
@@ -207,16 +211,25 @@ pub enum StmtKind {
/// A function definition. Output is None when the function returns nothing
/// meaning void, otherwise it is the name of the type the function
/// returns.
- DefineFunction {
- identifier: String,
- inputs: Vec<FunctionInput>,
- output: Option<String>,
- body: Box<Stmt>,
- },
+ DefineFunction(Function),
Return(Expr),
}
#[derive(PartialEq, Clone, Debug)]
+pub struct Function {
+ pub identifier: String,
+ pub inputs: Vec<FunctionInput>,
+ pub output: Option<String>,
+ pub kind: FunctionKind,
+}
+
+#[derive(PartialEq, Clone, Debug)]
+pub enum FunctionKind {
+ Normal { body: Box<Stmt> },
+ Foreign,
+}
+
+#[derive(PartialEq, Clone, Debug)]
pub struct FunctionInput {
pub identifier: String,
pub typ: String,
@@ -259,7 +272,10 @@ impl Display for Literal {
Literal::Float(f) => format!("{f}"),
Literal::Boolean(b) => format!("{b}"),
Literal::Character(c) => format!("'{c}'"),
- Literal::String(s) => format!("\"{s}\""),
+ Literal::String(s) => format!(
+ "\\\"{}\\\"",
+ s.replace('\"', "\\\"").replace("\\n", "\\\\n")
+ ),
Literal::Array(..) => "<Array>".to_string(),
};
diff --git a/sloth/src/parser/graph.rs b/sloth/src/parser/graph.rs
index da4bd71..23f46fe 100644
--- a/sloth/src/parser/graph.rs
+++ b/sloth/src/parser/graph.rs
@@ -1,24 +1,31 @@
use std::fmt::{Error, Write};
-use super::ast::{Expr, ExprKind, Stmt, StmtKind};
+use super::ast::{Expr, ExprKind, Function, FunctionKind, Stmt, StmtKind};
pub struct GraphBuilder {
graph: String,
}
impl GraphBuilder {
- pub fn generate(ast: &[Stmt]) -> Result<String, Error> {
+ pub fn generate(source: Option<&str>, ast: &Stmt) -> Result<String, Error> {
let mut this = Self {
graph: String::new(),
};
this.graph.push_str("digraph {\n");
- for stmt in ast.iter() {
- this.traverse_stmt0(stmt)?;
- }
- for stmt in ast.iter() {
- this.traverse_stmt(stmt)?;
+
+ if let Some(source) = source {
+ let source = source
+ .replace('\"', "\\\"")
+ .replace("\\n", "\\\\n")
+ .replace('\n', "\\l");
+
+ this.graph.push_str(&format!("label = \"{source}\";"));
+ this.graph.push_str("labeljust = l; labelloc = t;");
}
+
+ this.traverse_stmt0(ast)?;
+ this.traverse_stmt(ast)?;
this.graph.push('}');
Ok(this.graph)
@@ -72,7 +79,7 @@ impl GraphBuilder {
} => {
writeln!(
&mut self.graph,
- "N{} [shape=box label=\"DefineVariable\\n\\nIdentifier={}\\nType={}\"];",
+ "N{} [shape=box label=\"DefineVariable\\n\\nIdentifier={}\\lType={}\\l\"];",
stmt.id, identifier, typ
)?;
self.traverse_expr0(value)?;
@@ -85,22 +92,30 @@ impl GraphBuilder {
)?;
self.traverse_expr0(value)?;
}
- StmtKind::DefineFunction {
+ StmtKind::DefineFunction(Function {
identifier,
inputs,
output,
- body,
- } => {
+ kind,
+ }) => {
writeln!(
&mut self.graph,
"N{} [shape=box \
- label=\"DefineFunction\\n\\nIdentifier={}\\nInputs={}\\nOutput={}\"];",
+ label=\"DefineFunction\\n\\nIdentifier={}\\lInputs={}\\lOutput={}\\lKind={}\\\
+ l\"];",
stmt.id,
identifier,
inputs.len(),
- output.is_some()
+ output.is_some(),
+ match kind {
+ FunctionKind::Normal { .. } => "Normal",
+ FunctionKind::Foreign => "Foreign",
+ }
)?;
- self.traverse_stmt0(body)?;
+
+ if let FunctionKind::Normal { body } = kind {
+ self.traverse_stmt0(body)?;
+ }
}
StmtKind::Return(expr) => {
writeln!(
@@ -120,7 +135,7 @@ impl GraphBuilder {
ExprKind::Grouping(child) => {
writeln!(
&mut self.graph,
- "N{} [shape=circle label=\"Grouping\"];",
+ "N{} [shape=box style=rounded label=\"Grouping\"];",
expr.id
)?;
self.traverse_expr0(child)?;
@@ -128,21 +143,21 @@ impl GraphBuilder {
ExprKind::Literal(literal) => {
writeln!(
&mut self.graph,
- "N{} [shape=diamond label=\"Literal\\n\\nValue={}\"];",
+ "N{} [shape=box style=\"filled,rounded\" label=\"{}\"];",
expr.id, literal
)?;
}
ExprKind::Identifier(identifier) => {
writeln!(
&mut self.graph,
- "N{} [shape=diamond label=\"Identifier\\n\\nIdentifier={}\"];",
+ "N{} [shape=box style=\"filled,rounded\" label=\"{}\"];",
expr.id, identifier
)?;
}
ExprKind::BinaryOp { op, lhs, rhs } => {
writeln!(
&mut self.graph,
- "N{} [shape=circle label=\"{}\"];",
+ "N{} [shape=box style=rounded label=\"{}\"];",
expr.id, op
)?;
self.traverse_expr0(lhs)?;
@@ -151,7 +166,7 @@ impl GraphBuilder {
ExprKind::UnaryOp { op, value } => {
writeln!(
&mut self.graph,
- "N{} [shape=circle label=\"Unary {}\"];",
+ "N{} [shape=box style=rounded label=\"{}\"];",
expr.id, op
)?;
self.traverse_expr0(value)?;
@@ -159,7 +174,7 @@ impl GraphBuilder {
ExprKind::Call { callee, args } => {
writeln!(
&mut self.graph,
- "N{} [shape=circle label=\"Function Call\"];",
+ "N{} [shape=box style=rounded label=\"Function Call\"];",
expr.id
)?;
self.traverse_expr0(callee)?;
@@ -185,10 +200,19 @@ impl GraphBuilder {
self.traverse_expr(expr)?;
}
StmtKind::IfStmt {
- if_then, else_then, ..
+ condition,
+ if_then,
+ else_then,
+ ..
} => {
writeln!(
&mut self.graph,
+ "N{} -> N{} [label = \"Condition\"];",
+ stmt.id, condition.id
+ )?;
+ self.traverse_expr(condition)?;
+ writeln!(
+ &mut self.graph,
"N{} -> N{} [label = \"If Then\"];",
stmt.id, if_then.id
)?;
@@ -224,15 +248,21 @@ impl GraphBuilder {
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::DefineFunction(Function { kind, .. }) => {
+ if let FunctionKind::Normal { body } = kind {
+ writeln!(
+ &mut self.graph,
+ "N{} -> N{} [label = \"Body\"];",
+ stmt.id, body.id
+ )?;
+
+ self.traverse_stmt(body)?;
+ }
+ }
+ StmtKind::Return(value) => {
+ writeln!(&mut self.graph, "N{} -> N{};", stmt.id, value.id)?;
+ self.traverse_expr(value)?;
}
- StmtKind::Return(_) => (),
}
Ok(())
@@ -255,10 +285,14 @@ impl GraphBuilder {
self.traverse_expr(value)?;
}
ExprKind::Call { callee, args } => {
- writeln!(&mut self.graph, "N{} -> N{};", expr.id, callee.id)?;
+ writeln!(
+ &mut self.graph,
+ "N{} -> N{} [label=callee];",
+ expr.id, callee.id
+ )?;
self.traverse_expr(callee)?;
for arg in args {
- writeln!(&mut self.graph, "N{} -> N{};", expr.id, arg.id)?;
+ writeln!(&mut self.graph, "N{} -> N{} [label=arg];", expr.id, arg.id)?;
self.traverse_expr(arg)?;
}
}
diff --git a/sloth/src/parser/stmt.rs b/sloth/src/parser/stmt.rs
index 7897e21..973b9c3 100644
--- a/sloth/src/parser/stmt.rs
+++ b/sloth/src/parser/stmt.rs
@@ -1,4 +1,4 @@
-use super::ast::{FunctionInput, Stmt, StmtKind};
+use super::ast::{Function, FunctionInput, FunctionKind, Stmt, StmtKind};
use super::{AstParser, ParsingError};
use crate::lexer::TokenType;
@@ -7,10 +7,12 @@ impl<'a> AstParser<'a> {
match self.peek().tt {
TokenType::OpeningBrace => self.block(),
+ TokenType::Foreign => self.foreign(),
+
TokenType::If => self.if_stmt(),
TokenType::While => self.while_stmt(),
TokenType::Var => self.define_variable(),
- TokenType::Fn => self.define_function(),
+ TokenType::Fn => self.define_function(false),
TokenType::Return => self.return_stmt(),
_ if self.peek2().tt == TokenType::Eq => self.assign_variable(),
@@ -18,6 +20,17 @@ impl<'a> AstParser<'a> {
}
}
+ fn foreign(&mut self) -> Result<Stmt, ParsingError> {
+ // Consume the foreign token
+ self.consume(TokenType::Foreign, "Expected foreign")?;
+
+ match self.peek().tt {
+ TokenType::Fn => self.define_function(true),
+
+ _ => Err(ParsingError::UnexpectedToken),
+ }
+ }
+
fn if_stmt(&mut self) -> Result<Stmt, ParsingError> {
// Consume the if token
self.consume(TokenType::If, "Expected if")?;
@@ -101,7 +114,7 @@ impl<'a> AstParser<'a> {
}
// TODO: Make argument types optional
- fn define_function(&mut self) -> Result<Stmt, ParsingError> {
+ fn define_function(&mut self, is_foreign: bool) -> Result<Stmt, ParsingError> {
// Consume the fn token
self.consume(TokenType::Fn, "Expected fn")?;
@@ -120,6 +133,12 @@ impl<'a> AstParser<'a> {
identifier: input_identifier,
typ: input_type,
});
+
+ if self.peek().tt != TokenType::Comma {
+ break;
+ }
+
+ self.consume(TokenType::Comma, "Expected ','")?;
}
self.consume(TokenType::ClosingParen, "Expected ')'")?;
@@ -131,20 +150,27 @@ impl<'a> AstParser<'a> {
None
};
- // Get the function body
- let body = self.block()?;
+ // Get the function kind
+ let kind = if is_foreign {
+ self.consume(TokenType::SemiColon, "Expected semicolon")?;
+ FunctionKind::Foreign
+ } else {
+ FunctionKind::Normal {
+ body: Box::new(self.block()?),
+ }
+ };
- let kind = StmtKind::DefineFunction {
+ let stmt = StmtKind::DefineFunction(Function {
identifier,
inputs,
output,
- body: body.into(),
- };
+ kind,
+ });
Ok(Stmt::new(
self.reserve_id(),
self.line,
- kind,
+ stmt,
self.top.clone(),
))
}
@@ -229,7 +255,9 @@ mod tests {
use super::{AstParser, StmtKind};
use crate::lexer::Lexer;
- use crate::parser::ast::{BinaryOp, Expr, ExprKind, FunctionInput, Literal, Stmt};
+ use crate::parser::ast::{
+ BinaryOp, Expr, ExprKind, Function, FunctionInput, FunctionKind, Literal, Stmt,
+ };
use crate::symtable::SymbolTable;
#[test]
@@ -301,49 +329,60 @@ mod tests {
)
.collect_vec();
- let expected_ast = Ok(Stmt::without_table(11, StmtKind::DefineFunction {
- identifier: "foo".to_owned(),
- inputs: vec![FunctionInput {
- identifier: "bar".to_owned(),
- typ: "Int".to_owned(),
- }],
- output: Some("Int".to_owned()),
- body: Box::new(Stmt::without_table(
- 10,
- StmtKind::Block(vec![
- Stmt::without_table(3, StmtKind::DefineVariable {
- identifier: "baz".to_owned(),
- value: Expr::without_table(2, ExprKind::BinaryOp {
- op: BinaryOp::Add,
- lhs: Box::new(Expr::without_table(
- 0,
- ExprKind::Identifier("bar".to_owned()),
- )),
- rhs: Box::new(Expr::without_table(1, Literal::Integer(1).into())),
- }),
- typ: "Int".to_owned(),
- }),
- Stmt::without_table(7, StmtKind::AssignVariable {
- identifier: "baz".to_owned(),
- value: Expr::without_table(6, ExprKind::BinaryOp {
- op: BinaryOp::Add,
- lhs: Box::new(Expr::without_table(
- 4,
- ExprKind::Identifier("baz".to_owned()),
- )),
- rhs: Box::new(Expr::without_table(5, Literal::Integer(1).into())),
- }),
- }),
- Stmt::without_table(
- 9,
- StmtKind::Return(Expr::without_table(
- 8,
- ExprKind::Identifier("baz".to_owned()),
- )),
- ),
- ]),
- )),
- }));
+ let expected_ast = Ok(Stmt::without_table(
+ 11,
+ StmtKind::DefineFunction(Function {
+ identifier: "foo".to_owned(),
+ inputs: vec![FunctionInput {
+ identifier: "bar".to_owned(),
+ typ: "Int".to_owned(),
+ }],
+ output: Some("Int".to_owned()),
+ kind: FunctionKind::Normal {
+ body: Box::new(Stmt::without_table(
+ 10,
+ StmtKind::Block(vec![
+ Stmt::without_table(3, StmtKind::DefineVariable {
+ identifier: "baz".to_owned(),
+ value: Expr::without_table(2, ExprKind::BinaryOp {
+ op: BinaryOp::Add,
+ lhs: Box::new(Expr::without_table(
+ 0,
+ ExprKind::Identifier("bar".to_owned()),
+ )),
+ rhs: Box::new(Expr::without_table(
+ 1,
+ Literal::Integer(1).into(),
+ )),
+ }),
+ typ: "Int".to_owned(),
+ }),
+ Stmt::without_table(7, StmtKind::AssignVariable {
+ identifier: "baz".to_owned(),
+ value: Expr::without_table(6, ExprKind::BinaryOp {
+ op: BinaryOp::Add,
+ lhs: Box::new(Expr::without_table(
+ 4,
+ ExprKind::Identifier("baz".to_owned()),
+ )),
+ rhs: Box::new(Expr::without_table(
+ 5,
+ Literal::Integer(1).into(),
+ )),
+ }),
+ }),
+ Stmt::without_table(
+ 9,
+ StmtKind::Return(Expr::without_table(
+ 8,
+ ExprKind::Identifier("baz".to_owned()),
+ )),
+ ),
+ ]),
+ )),
+ },
+ }),
+ ));
let mut parser = AstParser::new(tokens, SymbolTable::new());
let generated_ast = parser.statement();
diff --git a/sloth/src/symtable.rs b/sloth/src/symtable.rs
index 2cb4741..b2bb209 100644
--- a/sloth/src/symtable.rs
+++ b/sloth/src/symtable.rs
@@ -52,6 +52,24 @@ impl SymbolTable {
None
}
+ pub fn get_type(&self, identifier: &str) -> Option<Type> {
+ let symbol = self.get(identifier)?;
+ if let Symbol::Type(ref typ) = *symbol {
+ return Some(typ.clone());
+ }
+
+ None
+ }
+
+ pub fn get_value(&self, identifier: &str) -> Option<Type> {
+ let symbol = self.get(identifier)?;
+ if let Symbol::Value(ref typ) = *symbol {
+ return Some(typ.clone());
+ }
+
+ None
+ }
+
pub fn get_mut(&self, identifier: &str) -> Option<RefMut<'_, Symbol>> {
for scope in self.iter() {
let reference = scope.symbols.borrow_mut();
@@ -108,18 +126,21 @@ impl<'a> Iterator for Iter<'a> {
}
#[derive(Debug)]
-pub struct Symbol {
- pub typ: SymbolType,
+pub enum Symbol {
+ /// Symbol referencing a compile time type, such as the Int symbol
+ Type(Type),
+ /// Symbol referencing a runtime value, such as the println symbol
+ Value(Type),
}
-impl Symbol {
- pub fn new(typ: SymbolType) -> Self {
- Self { typ }
- }
-}
-
-#[derive(Debug)]
-pub enum SymbolType {
- Variable,
- Function,
+#[derive(Clone, Debug, PartialEq, PartialOrd)]
+pub enum Type {
+ Void,
+ Integer,
+ Float,
+ Boolean,
+ Function {
+ inputs: Vec<Type>,
+ output: Box<Type>,
+ },
}