Skip to content

Commit

Permalink
Refactoring modules.
Browse files Browse the repository at this point in the history
  • Loading branch information
sidereusnuntius committed Nov 5, 2024
1 parent 33cc8f6 commit c2f9c8b
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 120 deletions.
1 change: 1 addition & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
fn main() {
// lalrpop::Configuration::new()..process_file(path)..process_dir("src/parser").unwrap();
lalrpop::process_root().unwrap();
}
8 changes: 6 additions & 2 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ pub enum Statement {
}

pub enum Expr {
Number(i32),
Number(bool, Box<Expr>),
Integer(i32),
Float(f32),
Id(Identifier),
Op(Box<Expr>, Opcode, Box<Expr>),
Predicate(Box<Expr>, Opcode, Box<Expr>),
Expand Down Expand Up @@ -65,7 +67,9 @@ impl fmt::Debug for Opcode {
impl fmt::Debug for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", match self {
Expr::Number(n) => format!("{n}"),
Expr::Number(sign, num) => format!("{}{:?}", if *sign { "-" } else { "" }, num),
Expr::Integer(n) => format!("{n}"),
Expr::Float(n) => format!("{n}"),
Expr::Op(l, op, r) => format!("({:?} {op:?} {:?})",
*l, *r),
Expr::Predicate(l, op, r) => format!("({:?} {op:?} {:?})",
Expand Down
107 changes: 2 additions & 105 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,105 +1,2 @@
use lalrpop_util::lalrpop_mod;

lalrpop_mod!(pub vit);

pub mod ast;

#[cfg(test)]
mod tests {
use std::result;

use super::*;

#[test]
fn test_declaration() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("let a; let b; let c = 24;").is_ok());
}

#[test]
fn test_missing_semicolon() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("let a").is_err());
assert!(parser.parse("let a = 23").is_err());
}


#[test]
fn test_invalid_assignment() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("let a = ").is_err());
assert!(parser.parse("a =").is_err());
assert!(parser.parse("a = -").is_err());
}

#[test]
fn test_invalid_id() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("let 2a = 23;").is_err());
assert!(parser.parse("let + = 23;").is_err());
assert!(parser.parse("let = = 23;").is_err());
assert!(parser.parse("let 24 = 23;").is_err());
}

#[test]
fn test_keyword_id(){
let parser = vit::ProgramParser::new();

assert!(parser.parse("let let;").is_err());
assert!(parser.parse("let read;").is_err());
}

#[test]
fn test_valid_expression() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("let a = 23 + 24;").is_ok());
assert!(parser.parse("let a = 23 + 8 ^ 2 * 3;").is_ok());
}

#[test]
fn test_precedence() {
let parser = vit::ProgramParser::new();

if let Ok(result) = parser.parse("let a = 23 + 8 ^ 2 * 3;") {
if let ast::Statement::Declaration(id, expression) = result.get(0).unwrap() {
assert_eq!(String::from("Some((23 + ((8 ^ 2) * 3)))"), format!("{:?}", expression));
assert_eq!(String::from("a"), id.clone());
}
}
}

#[test]
fn test_simple_if() {
let parser = vit::ProgramParser::new();
let result = parser.parse("if 2 == 2 { }");
if let Ok(statement) = result {
assert_eq!("[If((2 == 2), [], None)]", format!("{statement:?}"));
}
}

fn test_complex_if() {
let parser = vit::ProgramParser::new();
let result = parser.parse("if a % 2 == 0 and (b > a or a == 4) { }");
if let Ok(statement) = result {
assert_eq!("[If(((a % 2) and ((b > a) or (a == 4))), [], None)]", format!("{statement:?}"));
}

let result = parser.parse("if a % 2 == 0 and b > a or a == 4 { }");
if let Ok(statement) = result {
assert_eq!("[If(((((a % 2) == 0) and (b > a)) or (a == 4))), [], None)]", format!("{statement:?}"));
}
}

#[test]
fn test_if_with_invalid_expression() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("if 4 { }").is_err());
assert!(parser.parse("if b { }").is_err());
}
}
pub mod parser;
mod ast;
11 changes: 1 addition & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,7 @@ pub mod ast;
fn main() {

let expr = vit::ProgramParser::new()
.parse("\
let a = 0;
loop {
write a;
a = a + 1;
if a == 10 {
break;
}
}
write 'END OF THE PROGRAM\n';")
.parse("c = 2 + - 2.0;")
.unwrap();
println!("{expr:?}");
}
118 changes: 118 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
use lalrpop_util::lalrpop_mod;
use crate::ast::Statement;

lalrpop_mod!(pub vit);

#[cfg(test)]
#[allow(dead_code)]
mod tests {
use super::*;

#[test]
fn test_declaration() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("let a; let b; let c = 24;").is_ok());
}

#[test]
fn test_missing_semicolon() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("let a").is_err());
assert!(parser.parse("let a = 23").is_err());
}


#[test]
fn test_invalid_assignment() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("let a = ").is_err());
assert!(parser.parse("a =").is_err());
assert!(parser.parse("a = -").is_err());
}

#[test]
fn test_invalid_id() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("let 2a = 23;").is_err());
assert!(parser.parse("let + = 23;").is_err());
assert!(parser.parse("let = = 23;").is_err());
assert!(parser.parse("let 24 = 23;").is_err());
}

#[test]
fn test_keyword_id(){
let parser = vit::ProgramParser::new();

assert!(parser.parse("let let;").is_err());
assert!(parser.parse("let read;").is_err());
}

#[test]
fn test_valid_expression() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("let a = 23 + 24;").is_ok());
assert!(parser.parse("let a = 23 + 8 ^ 2 * 3;").is_ok());
}

#[test]
fn test_precedence() {
let parser = vit::ProgramParser::new();

if let Ok(result) = parser.parse("let a = 23 + 8 ^ 2 * 3;") {
if let Statement::Declaration(id, expression) = result.get(0).unwrap() {
assert_eq!(String::from("Some((23 + ((8 ^ 2) * 3)))"), format!("{:?}", expression));
assert_eq!(String::from("a"), id.clone());
}
}
}

#[test]
fn test_simple_if() {
let parser = vit::ProgramParser::new();
let result = parser.parse("if 2 == 2 { }");
if let Ok(statement) = result {
assert_eq!("[If((2 == 2), [], None)]", format!("{statement:?}"));
}
}

fn test_complex_if() {
let parser = vit::ProgramParser::new();
let result = parser.parse("if a % 2 == 0 and (b > a or a == 4) { }");
if let Ok(statement) = result {
assert_eq!("[If(((a % 2) and ((b > a) or (a == 4))), [], None)]", format!("{statement:?}"));
}

let result = parser.parse("if a % 2 == 0 and b > a or a == 4 { }");
if let Ok(statement) = result {
assert_eq!("[If(((((a % 2) == 0) and (b > a)) or (a == 4))), [], None)]", format!("{statement:?}"));
}
}

#[test]
fn test_if_with_invalid_expression() {
let parser = vit::ProgramParser::new();

assert!(parser.parse("if 4 { }").is_err());
assert!(parser.parse("if b { }").is_err());
}

#[test]
fn test_do_until() {
let parser = vit::ProgramParser::new();
assert!(parser.parse("\
let a = 0;
loop {
write a;
a = a + 1;
if a == 10 {
break;
}
}
write 'END OF THE PROGRAM\n';").is_ok());
}
}
8 changes: 5 additions & 3 deletions src/vit.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,12 @@ Expop: Opcode = {

Term: Box<Expr> = {
"(" <Expr> ")",
Num => Box::new(Expr::Number(<>)),
<sign:"-"?> <n:Num> => Box::new(Expr::Number(sign.is_some(), n)),
ID => Box::new(Expr::Id(<>)),
}

Num: i32 = r"[0-9]+" => i32::from_str(<>).unwrap();
ID: Identifier = r"[a-zA-z_][a-zA-z0-9_]*" => String::from(<>);
//Num: i32 = r"[0-9]+" => i32::from_str(<>).unwrap();
Num: Box<Expr> = <n:r"([0-9]+.)?[0-9]+"> => if n.contains('.') { Box::new(Expr::Float(f32::from_str(n).unwrap())) } else { Box::new(Expr::Integer(i32::from_str(<>).unwrap())) };
// Float: f32 = r"[0-9]+.[0-9]+" => Float(f32::from_str(<>).unwrap());
ID: Identifier = r"[a-zA-z][a-zA-z0-9_]*" => String::from(<>);
Literal: String = r#"'(?:[^"\\]|\\.)*'"# => String::from(<>);

0 comments on commit c2f9c8b

Please sign in to comment.