Skip to content

Commit

Permalink
Parser: add expr_to_line_number function
Browse files Browse the repository at this point in the history
  • Loading branch information
Ernest1338 committed Jan 21, 2025
1 parent 0f7f674 commit d0183f8
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 19 deletions.
25 changes: 14 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{
compiler::Compiler,
interpreter::Interpreter,
parser::expr_to_line_number,
utils::{display_error, display_error_stdout, ErrorType},
};
use std::{
Expand All @@ -14,11 +15,12 @@ use std::{
// - if, else expr
// - fn expr
// - type checker
// - static build, static qbe in release gh
// - static qbe in release gh
// - linter
// - formatter
// - build system (toml? github repos as packages. line eg. Ernest1338/package = "0.1")
// - more test cases
// - build for arm64 in actions, upload artifacts

mod args;
use args::get_args;
Expand Down Expand Up @@ -108,13 +110,14 @@ fn main() {
// -------------------
// Reading source code
// -------------------
let source_code = match args.input {
let orig_source_code = match args.input {
Some(input) => match read_to_string(input) {
Ok(input) => input,
Err(_) => {
display_error(ErrorType::Generic(
"Could not read source code file".to_string(),
));
display_error(
ErrorType::Generic("Could not read source code file".to_string()),
Some(1),
);
exit(1);
}
},
Expand All @@ -124,15 +127,15 @@ fn main() {
// -------------
// Preprocessing
// -------------
let source_code = measure_time("Preprocessing", || preprocess(&source_code));
let source_code = measure_time("Preprocessing", || preprocess(&orig_source_code));

// ----------------
// Lexical Analysis
// ----------------
let tokens = measure_time("Lexical Analysis", || match lexer(&source_code) {
Ok(tokens) => tokens,
Err(err) => {
display_error(ErrorType::SyntaxError(err));
display_error(ErrorType::SyntaxError(err), Some(1));
exit(1);
}
});
Expand All @@ -145,7 +148,7 @@ fn main() {
let ast = measure_time("Parsing", || match parser.parse() {
Ok(ast) => ast,
Err(err) => {
display_error(ErrorType::SyntaxError(err));
display_error(ErrorType::SyntaxError(err), Some(1));
exit(1);
}
});
Expand All @@ -158,7 +161,7 @@ fn main() {
let mut interpreter = Interpreter::from_ast(ast);
measure_time("Interpreter Execution", || {
if let Err(err) = interpreter.run() {
display_error(err);
display_error(err, Some(1));
exit(1);
}
});
Expand All @@ -169,7 +172,7 @@ fn main() {
let mut compiler = Compiler::from_ast(ast);
measure_time("Full Compiler Execution", || {
if let Err(err) = compiler.compile(args.output.clone()) {
display_error(err);
display_error(err, Some(1));
exit(1);
}
});
Expand All @@ -190,7 +193,7 @@ fn main() {
let mut compiler = Compiler::from_ast(ast);
measure_time("Full Compiler Execution", || {
if let Err(err) = compiler.compile(args.output) {
display_error(err);
display_error(err, Some(1));
exit(1);
}
});
Expand Down
54 changes: 49 additions & 5 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,52 @@ pub fn lexer(input: &str) -> Result<Vec<Token>, String> {
Ok(tokens)
}

/// Finds expr in the source provided in the argument. Returns a line number as usize
pub fn expr_to_line_number(expr: &Expr, source: &str) -> Option<usize> {
let mut current_line = 1;

let mut context = String::new();

// Iterate through the source line by line
for line in source.lines() {
// Handle line comments and empty lines
if line.starts_with("//") || line.is_empty() {
current_line += 1;
continue;
}

// Handle inline comments
let line = line.split("//").collect::<Vec<&str>>()[0];

// Append context
context.push_str(&format!("{line}\n"));

let context_tokens: Vec<Token> = lexer(&context).unwrap_or_default();

// Use the parser to parse the tokens of the current context
let mut parser = Parser::new(&context_tokens);

match parser.parse_expr() {
Ok(parsed_expr) => {
// Clear current context
context.clear();
// Compare the parsed expression with the given expression
if *expr == parsed_expr {
return Some(current_line);
}
}
Err(_) => continue,
}

// Increment current line counter
current_line += 1;
}

None
}

/// Represents a parsed expression in the abstract syntax tree (AST)
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
#[allow(clippy::enum_variant_names)]
pub enum Expr {
FuncCall(FuncCall),
Expand All @@ -210,30 +254,30 @@ pub enum Expr {
}

/// Represents a variable declaration in the AST
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct VariableDeclaration {
pub identifier: String,
pub typ: Option<Type>,
pub value: Expr,
}

/// Represents a function call in the AST
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct FuncCall {
pub name: String,
pub arguments: Vec<Expr>,
}

/// Represents a binary expression in the AST
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub struct BinExpr {
pub lhs: Expr,
pub rhs: Expr,
pub kind: BinOpKind,
}

/// Represents kinds of binary operators
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum BinOpKind {
Plus,
Minus,
Expand Down
10 changes: 7 additions & 3 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,13 +150,17 @@ pub enum ErrorType {
}

/// Display error to the user in a pretty way
pub fn display_error(err: ErrorType) {
pub fn display_error(err: ErrorType, line: Option<usize>) {
let line = match line {
Some(line) => &format!(" on line {line}:"),
None => "",
};
match err {
ErrorType::SyntaxError(s) => {
eprintln!("{} {s}", color("[Syntax Error]", Color::LightRed))
eprintln!("{}{line} {s}", color("[Syntax Error]", Color::LightRed),);
}
ErrorType::Generic(s) => {
eprintln!("{} {s}", color("[Error]", Color::LightRed))
eprintln!("{}{line} {s}", color("[Error]", Color::LightRed))
}
};
}
Expand Down

0 comments on commit d0183f8

Please sign in to comment.