Skip to content

Commit

Permalink
handled most of the errors properly
Browse files Browse the repository at this point in the history
  • Loading branch information
mainak55512 committed Oct 17, 2024
1 parent b2b8fb1 commit edd3998
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 101 deletions.
6 changes: 3 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let cli = Cli::parse();

let content = if let Some(load) = cli.load.as_deref() {
fs::read_to_string(load).map_err(|err| err.to_string())?
fs::read_to_string(load).map_err(|_| "File not found or couldn't read from file")?
} else {
io::stdin()
.lock()
Expand All @@ -38,7 +38,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let content = serde_json::from_str::<Vec<Value>>(&content)?;

let query_string = cli.query.as_deref().unwrap_or_default();
let query = Query::new(query_string);
let query = Query::new(query_string)?;

let params = cli.params.unwrap_or_default();
let params = params
Expand Down Expand Up @@ -66,7 +66,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// apply the query and params to content.
let mut output = Vec::new();
for obj in &content {
if query.eval(obj) {
if query.eval(obj)? {
output.push(filter(obj));
}
}
Expand Down
14 changes: 7 additions & 7 deletions src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ pub struct Query {
}

impl Query {
pub fn new(query: &str) -> Self {
pub fn new(query: &str) -> Result<Self, Box<dyn std::error::Error>> {
let mut tokens = lexer::tokenize(query);
let ast = parser::parse_ast(&mut tokens);
Self { ast }
let ast = parser::parse_ast(&mut tokens)?;
Ok(Self { ast })
}

pub fn eval(&self, obj: &Value) -> bool {
if let RuntimeType::Bool(result) = interpreter::eval_ast_stmt(obj, &self.ast) {
result
pub fn eval(&self, obj: &Value) -> Result<bool, Box<dyn std::error::Error>> {
if let RuntimeType::Bool(result) = interpreter::eval_ast_stmt(obj, &self.ast)? {
Ok(result)
} else {
false
Ok(false)
}
}
}
114 changes: 50 additions & 64 deletions src/query/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ pub enum RuntimeType {
Bool(bool),
}

pub(super) fn eval_ast_stmt(obj: &Value, ast: &ASTNode) -> RuntimeType {
pub(super) fn eval_ast_stmt(
obj: &Value,
ast: &ASTNode,
) -> Result<RuntimeType, Box<dyn std::error::Error>> {
let kind = match ast {
ASTNode::PrimarySymbol(ast) => ast.kind,
ASTNode::BinaryExpr(ast) => ast.kind,
Expand All @@ -17,37 +20,40 @@ pub(super) fn eval_ast_stmt(obj: &Value, ast: &ASTNode) -> RuntimeType {
match kind {
LiteralType::LogicalExpr => eval_logical_expr(obj, ast),
LiteralType::BinaryExpr => eval_binary_expr(obj, ast),
LiteralType::NumericLiteral => RuntimeType::Element(ast.clone()),
LiteralType::StringLiteral => RuntimeType::Element(ast.clone()),
LiteralType::BinaryOperator => RuntimeType::Bool(false),
LiteralType::NoneType => RuntimeType::Bool(true),
LiteralType::NumericLiteral => Ok(RuntimeType::Element(ast.clone())),
LiteralType::StringLiteral => Ok(RuntimeType::Element(ast.clone())),
LiteralType::BinaryOperator => Ok(RuntimeType::Bool(false)),
LiteralType::NoneType => Ok(RuntimeType::Bool(true)),
}
}

fn eval_logical_expr(obj: &Value, ast: &ASTNode) -> RuntimeType {
fn eval_logical_expr(
obj: &Value,
ast: &ASTNode,
) -> Result<RuntimeType, Box<dyn std::error::Error>> {
if let ASTNode::BinaryExpr(ref ast) = ast {
let lhs = eval_ast_stmt(obj, &ast.left);
let rhs = eval_ast_stmt(obj, &ast.right);
return _eval_logical_expr(lhs, rhs, &ast.operator);
let lhs = eval_ast_stmt(obj, &ast.left)?;
let rhs = eval_ast_stmt(obj, &ast.right)?;
return Ok(_eval_logical_expr(lhs, rhs, &ast.operator));
}
RuntimeType::Bool(false)
Ok(RuntimeType::Bool(false))
}

fn eval_binary_expr(obj: &Value, ast: &ASTNode) -> RuntimeType {
fn eval_binary_expr(obj: &Value, ast: &ASTNode) -> Result<RuntimeType, Box<dyn std::error::Error>> {
if let ASTNode::BinaryExpr(ref ast) = ast {
let lhs = eval_ast_stmt(obj, &ast.left);
let rhs = eval_ast_stmt(obj, &ast.right);
let lhs = eval_ast_stmt(obj, &ast.left)?;
let rhs = eval_ast_stmt(obj, &ast.right)?;
return _eval_binary_expr(obj, lhs, rhs, &ast.operator);
}
RuntimeType::Bool(false)
Ok(RuntimeType::Bool(false))
}

fn _eval_binary_expr(
obj: &Value,
lhs: RuntimeType,
rhs: RuntimeType,
operator: &str,
) -> RuntimeType {
) -> Result<RuntimeType, Box<dyn std::error::Error>> {
let left = if let RuntimeType::Element(ASTNode::PrimarySymbol(val)) = &lhs {
&val.symbol
} else {
Expand All @@ -61,66 +67,46 @@ fn _eval_binary_expr(

match operator {
"=" => match right_node_type {
LiteralType::NumericLiteral => RuntimeType::Bool(
get_value_from_obj(obj, left)
.to_string()
.parse::<f64>()
.expect("Not a Number")
== right.parse::<f64>().expect("Not a Number"),
),
_ => RuntimeType::Bool(get_value_from_obj(obj, left) == right),
LiteralType::NumericLiteral => Ok(RuntimeType::Bool(
get_value_from_obj(obj, left).to_string().parse::<f64>()?
== right.parse::<f64>()?,
)),
_ => Ok(RuntimeType::Bool(get_value_from_obj(obj, left) == right)),
},
">" => match right_node_type {
LiteralType::NumericLiteral => RuntimeType::Bool(
get_value_from_obj(obj, left)
.to_string()
.parse::<f64>()
.expect("Not a Number")
> right.parse::<f64>().expect("Not a Number"),
),
_ => RuntimeType::Bool(false),
LiteralType::NumericLiteral => Ok(RuntimeType::Bool(
get_value_from_obj(obj, left).to_string().parse::<f64>()? > right.parse::<f64>()?,
)),
_ => Ok(RuntimeType::Bool(false)),
},
"<" => match right_node_type {
LiteralType::NumericLiteral => RuntimeType::Bool(
get_value_from_obj(obj, left)
.to_string()
.parse::<f64>()
.expect("Not a Number")
< right.parse::<f64>().expect("Not a Number"),
),
_ => RuntimeType::Bool(false),
LiteralType::NumericLiteral => Ok(RuntimeType::Bool(
get_value_from_obj(obj, left).to_string().parse::<f64>()? < right.parse::<f64>()?,
)),
_ => Ok(RuntimeType::Bool(false)),
},
">=" => match right_node_type {
LiteralType::NumericLiteral => RuntimeType::Bool(
get_value_from_obj(obj, left)
.to_string()
.parse::<f64>()
.expect("Not a Number")
>= right.parse::<f64>().expect("Not a Number"),
),
_ => RuntimeType::Bool(false),
LiteralType::NumericLiteral => Ok(RuntimeType::Bool(
get_value_from_obj(obj, left).to_string().parse::<f64>()?
>= right.parse::<f64>()?,
)),
_ => Ok(RuntimeType::Bool(false)),
},
"<=" => match right_node_type {
LiteralType::NumericLiteral => RuntimeType::Bool(
get_value_from_obj(obj, left)
.to_string()
.parse::<f64>()
.expect("Not a Number")
<= right.parse::<f64>().expect("Not a Number"),
),
_ => RuntimeType::Bool(false),
LiteralType::NumericLiteral => Ok(RuntimeType::Bool(
get_value_from_obj(obj, left).to_string().parse::<f64>()?
<= right.parse::<f64>()?,
)),
_ => Ok(RuntimeType::Bool(false)),
},
"!=" => match right_node_type {
LiteralType::NumericLiteral => RuntimeType::Bool(
get_value_from_obj(obj, left)
.to_string()
.parse::<f64>()
.expect("Not a Number")
!= right.parse::<f64>().expect("Not a Number"),
),
_ => RuntimeType::Bool(get_value_from_obj(obj, left) != right),
LiteralType::NumericLiteral => Ok(RuntimeType::Bool(
get_value_from_obj(obj, left).to_string().parse::<f64>()?
!= right.parse::<f64>()?,
)),
_ => Ok(RuntimeType::Bool(get_value_from_obj(obj, left) != right)),
},
_ => RuntimeType::Bool(false),
_ => Ok(RuntimeType::Bool(false)),
}
}

Expand Down
58 changes: 31 additions & 27 deletions src/query/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,58 +33,62 @@ pub struct BinaryExpr {
pub operator: String,
}

pub(super) fn parse_ast(tokens: &mut VecDeque<Token>) -> ASTNode {
pub(super) fn parse_ast(
tokens: &mut VecDeque<Token>,
) -> Result<ASTNode, Box<dyn std::error::Error>> {
if tokens.is_empty() {
return ASTNode::NoneType;
return Ok(ASTNode::NoneType);
}
let mut left = parse_binary_expr(tokens);
let mut left = parse_binary_expr(tokens)?;
if !tokens.is_empty() && tokens[0].val != "&&" && tokens[0].val != "||" {
println!("Query is invalid");
std::process::exit(1);
return Err("Query is invalid".into());
}
while !tokens.is_empty() && (tokens[0].val == "&&" || tokens[0].val == "||") {
let operator = tokens.pop_front().expect("Empty operator").val;
let operator = tokens.pop_front().ok_or("Empty operator")?.val;
if tokens.is_empty() {
println!("Query is invalid");
std::process::exit(1);
return Err("Query is invalid".into());
}
let right = parse_binary_expr(tokens);
let right = parse_binary_expr(tokens)?;
left = ASTNode::BinaryExpr(Box::new(BinaryExpr {
kind: LiteralType::LogicalExpr,
left,
right,
operator,
}))
}
left
Ok(left)
}

fn parse_primary_expr(token_array: &mut VecDeque<Token>) -> ASTNode {
fn parse_primary_expr(
token_array: &mut VecDeque<Token>,
) -> Result<ASTNode, Box<dyn std::error::Error>> {
let tk = &token_array[0].token_type;
match tk {
TokenType::Number => ASTNode::PrimarySymbol(PrimarySymbol {
TokenType::Number => Ok(ASTNode::PrimarySymbol(PrimarySymbol {
kind: LiteralType::NumericLiteral,
symbol: token_array.pop_front().expect("NaN").val,
}),
TokenType::String => ASTNode::PrimarySymbol(PrimarySymbol {
symbol: token_array.pop_front().ok_or("Not a Number")?.val,
})),
TokenType::String => Ok(ASTNode::PrimarySymbol(PrimarySymbol {
kind: LiteralType::StringLiteral,
symbol: token_array.pop_front().expect("Invalid String").val,
}),
TokenType::Binary => ASTNode::PrimarySymbol(PrimarySymbol {
symbol: token_array.pop_front().ok_or("Invalid String")?.val,
})),
TokenType::Binary => Ok(ASTNode::PrimarySymbol(PrimarySymbol {
kind: LiteralType::BinaryOperator,
symbol: token_array.pop_front().expect("Invalid Operator").val,
}),
symbol: token_array.pop_front().ok_or("Invalid Operator")?.val,
})),
TokenType::Paren => {
token_array.pop_front();
let value = parse_ast(token_array);
let value = parse_ast(token_array)?;
token_array.pop_front();
value
Ok(value)
}
}
}

fn parse_binary_expr(token_array: &mut VecDeque<Token>) -> ASTNode {
let mut left = parse_primary_expr(token_array);
fn parse_binary_expr(
token_array: &mut VecDeque<Token>,
) -> Result<ASTNode, Box<dyn std::error::Error>> {
let mut left = parse_primary_expr(token_array)?;
while !token_array.is_empty()
&& (token_array[0].val == "="
|| token_array[0].val == ">="
Expand All @@ -93,14 +97,14 @@ fn parse_binary_expr(token_array: &mut VecDeque<Token>) -> ASTNode {
|| token_array[0].val == "<"
|| token_array[0].val == "!=")
{
let operator = token_array.pop_front().expect("Invalid Operator").val;
let right = parse_primary_expr(token_array);
let operator = token_array.pop_front().ok_or("Invalid Operator")?.val;
let right = parse_primary_expr(token_array)?;
left = ASTNode::BinaryExpr(Box::new(BinaryExpr {
kind: LiteralType::BinaryExpr,
left,
right,
operator,
}))
}
left
Ok(left)
}

0 comments on commit edd3998

Please sign in to comment.