Skip to content

Commit

Permalink
Keep track of line numbers through to parser
Browse files Browse the repository at this point in the history
  • Loading branch information
cody-quinn committed Jun 24, 2023
1 parent a8b21eb commit 0ee365c
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 30 deletions.
22 changes: 16 additions & 6 deletions sloth/src/analysis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@ use crate::symtable::{Symbol, SymbolType};
#[derive(Debug, thiserror::Error)]
pub enum AnalysisError {
#[error("Mismatched types")]
TypeMismatch,
#[error("Unknown identifier '{0}'")]
UnknownIdentifier(String),
TypeMismatch(u32),
#[error("Unknown identifier '{1}'")]
UnknownIdentifier(u32, String),
#[error("Unknown error")]
Unknown,
Unknown(u32),
}

impl AnalysisError {
pub fn line(&self) -> u32 {
match self {
AnalysisError::TypeMismatch(line) => *line,
AnalysisError::UnknownIdentifier(line, ..) => *line,
AnalysisError::Unknown(line) => *line,
}
}
}

pub fn analyze(root: &mut Stmt) -> Result<(), AnalysisError> {
Expand Down Expand Up @@ -40,11 +50,11 @@ fn populate_symtable(node: &AstNode) {

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(identifier.clone()));
return Err(AnalysisError::UnknownIdentifier(expr.line, identifier.clone()));
}

if let AstNode::Stmt(stmt) = node && let StmtKind::AssignVariable { identifier, .. } = &stmt.kind && !stmt.symtable.clone().contains(identifier) {
return Err(AnalysisError::UnknownIdentifier(identifier.clone()));
return Err(AnalysisError::UnknownIdentifier(stmt.line, identifier.clone()));
}

for child in node.children() {
Expand Down
8 changes: 4 additions & 4 deletions sloth/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,11 @@ impl Location {

#[derive(Debug)]
pub struct Token<'a> {
pub tt: TokenType,
pub lexeme: &'a str,
pub(crate) tt: TokenType,
pub(crate) lexeme: &'a str,

start: Location,
end: Location,
pub start: Location,
pub end: Location,
}

pub struct Lexer<'a> {
Expand Down
6 changes: 4 additions & 2 deletions sloth/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ fn main() {
let mut ast = AstParser::parse(tokens, global_symtable).unwrap();

if let Err(error) = analyze(&mut ast) {
eprintln!("Failed to compile code:");
eprintln!("{error}");
eprintln!("Error on line {}: {error}", error.line() + 1);
return;
}

println!("{ast:#?}");

// let graph = GraphBuilder::generate(&ast).unwrap();
// println!("{graph}");
}
29 changes: 25 additions & 4 deletions sloth/src/parser/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,19 @@ impl<'a> AstNode<'a> {
}
children.into_iter()
}

pub fn line(&self) -> u32 {
match self {
Self::Expr(expr) => expr.line,
Self::Stmt(stmt) => stmt.line,
}
}
}

#[derive(Clone, Debug)]
pub struct Expr {
pub id: i32,
pub line: u32,
pub kind: ExprKind,
pub symtable: SymbolTable,
}
Expand All @@ -37,14 +45,20 @@ impl PartialEq for Expr {
}

impl Expr {
pub fn new(id: i32, kind: ExprKind, symtable: SymbolTable) -> Self {
Self { id, kind, symtable }
pub fn new(id: i32, line: u32, kind: ExprKind, symtable: SymbolTable) -> Self {
Self {
id,
line,
kind,
symtable,
}
}

/// Useful for testing
pub fn without_table(id: i32, kind: ExprKind) -> Self {
Self {
id,
line: 0,
kind,
symtable: SymbolTable::new(),
}
Expand Down Expand Up @@ -98,6 +112,7 @@ pub enum ExprKind {
#[derive(Clone, Debug)]
pub struct Stmt {
pub id: i32,
pub line: u32,
pub kind: StmtKind,
pub symtable: SymbolTable,
}
Expand All @@ -109,14 +124,20 @@ impl PartialEq for Stmt {
}

impl Stmt {
pub fn new(id: i32, kind: StmtKind, symtable: SymbolTable) -> Self {
Self { id, kind, symtable }
pub fn new(id: i32, line: u32, kind: StmtKind, symtable: SymbolTable) -> Self {
Self {
id,
line,
kind,
symtable,
}
}

/// Useful for testing
pub fn without_table(id: i32, kind: StmtKind) -> Self {
Self {
id,
line: 0,
kind,
symtable: SymbolTable::new(),
}
Expand Down
17 changes: 14 additions & 3 deletions sloth/src/parser/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ impl<'a> AstParser<'a> {
value: Box::new(value),
};

return Ok(Expr::new(self.reserve_id(), kind, self.top.clone()));
return Ok(Expr::new(
self.reserve_id(),
self.line,
kind,
self.top.clone(),
));
}

self.call()
Expand All @@ -45,6 +50,7 @@ impl<'a> AstParser<'a> {

expr = Expr::new(
self.reserve_id(),
self.line,
ExprKind::Call {
callee: Box::new(expr),
args: arguments,
Expand All @@ -70,7 +76,12 @@ impl<'a> AstParser<'a> {
_ => return Err(ParsingError::UnexpectedToken),
};

Ok(Expr::new(self.reserve_id(), kind, self.top.clone()))
Ok(Expr::new(
self.reserve_id(),
self.line,
kind,
self.top.clone(),
))
}
}

Expand All @@ -92,7 +103,7 @@ macro_rules! binary_expr {
rhs: Box::new(rhs),
};

expr = Expr::new(self.reserve_id(), kind, self.top.clone());
expr = Expr::new(self.reserve_id(), self.line, kind, self.top.clone());
}

Ok(expr)
Expand Down
11 changes: 8 additions & 3 deletions sloth/src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ pub enum ParsingError {

#[derive(Debug)]
pub struct AstParser<'a> {
top: SymbolTable,
tokens: Vec<Token<'a>>,
index: usize,
id: i32,
top: SymbolTable,
line: u32,
}

impl<'a> AstParser<'a> {
Expand All @@ -34,6 +35,7 @@ impl<'a> AstParser<'a> {

let root = Stmt::new(
parser.reserve_id(),
parser.line,
StmtKind::Block(statements),
parser.top.clone(),
);
Expand All @@ -46,10 +48,11 @@ impl<'a> AstParser<'a> {
impl<'a> AstParser<'a> {
pub fn new(tokens: Vec<Token<'a>>, root: SymbolTable) -> Self {
Self {
top: root,
tokens,
index: 0,
id: 0,
top: root,
line: 0,
}
}

Expand All @@ -66,8 +69,10 @@ impl<'a> AstParser<'a> {
return None;
}

let current = &self.tokens[self.index];
self.index += 1;
Some(&self.tokens[self.index - 1])
self.line = current.start.row;
Some(current)
}

pub fn advance_if(&mut self, next: impl FnOnce(&Token) -> bool) -> bool {
Expand Down
56 changes: 48 additions & 8 deletions sloth/src/parser/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ impl<'a> AstParser<'a> {
else_then: else_then.map(|it| it.into()),
};

Ok(Stmt::new(self.reserve_id(), kind, self.top.clone()))
Ok(Stmt::new(
self.reserve_id(),
self.line,
kind,
self.top.clone(),
))
}

fn while_stmt(&mut self) -> Result<Stmt, ParsingError> {
Expand All @@ -57,7 +62,12 @@ impl<'a> AstParser<'a> {
body: body.into(),
};

Ok(Stmt::new(self.reserve_id(), kind, self.top.clone()))
Ok(Stmt::new(
self.reserve_id(),
self.line,
kind,
self.top.clone(),
))
}

// TODO: Make variable types optional
Expand All @@ -82,7 +92,12 @@ impl<'a> AstParser<'a> {
typ,
};

Ok(Stmt::new(self.reserve_id(), kind, self.top.clone()))
Ok(Stmt::new(
self.reserve_id(),
self.line,
kind,
self.top.clone(),
))
}

// TODO: Make argument types optional
Expand Down Expand Up @@ -126,15 +141,25 @@ impl<'a> AstParser<'a> {
body: body.into(),
};

Ok(Stmt::new(self.reserve_id(), kind, self.top.clone()))
Ok(Stmt::new(
self.reserve_id(),
self.line,
kind,
self.top.clone(),
))
}

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")?;
let kind = StmtKind::Return(value);
Ok(Stmt::new(self.reserve_id(), kind, self.top.clone()))
Ok(Stmt::new(
self.reserve_id(),
self.line,
kind,
self.top.clone(),
))
}

fn assign_variable(&mut self) -> Result<Stmt, ParsingError> {
Expand All @@ -143,14 +168,24 @@ impl<'a> AstParser<'a> {
let value = self.expression()?;
self.consume(TokenType::SemiColon, "Expected ';' at end of statement")?;
let kind = StmtKind::AssignVariable { identifier, value };
Ok(Stmt::new(self.reserve_id(), kind, self.top.clone()))
Ok(Stmt::new(
self.reserve_id(),
self.line,
kind,
self.top.clone(),
))
}

fn expression_stmt(&mut self) -> Result<Stmt, ParsingError> {
let expr = self.expression()?;
self.consume(TokenType::SemiColon, "Expected ';' at end of statement")?;
let kind = StmtKind::ExprStmt(expr);
Ok(Stmt::new(self.reserve_id(), kind, self.top.clone()))
Ok(Stmt::new(
self.reserve_id(),
self.line,
kind,
self.top.clone(),
))
}

fn block(&mut self) -> Result<Stmt, ParsingError> {
Expand All @@ -171,7 +206,12 @@ impl<'a> AstParser<'a> {

let kind = StmtKind::Block(body);

Ok(Stmt::new(this.reserve_id(), kind, this.top.clone()))
Ok(Stmt::new(
this.reserve_id(),
this.line,
kind,
this.top.clone(),
))
}

// Push a table, call the inner function and then pop that table
Expand Down

0 comments on commit 0ee365c

Please sign in to comment.