Assignment 4 Done

This commit is contained in:
static
2024-10-09 13:18:03 +00:00
parent 03f169cd96
commit a6f41960ad
2 changed files with 84 additions and 3 deletions

View File

@@ -27,7 +27,26 @@ impl Context {
/// Calculates the given expression. (We assume the absence of overflow.)
pub fn calc_expression(&self, expression: &Expression) -> Result<f64> {
todo!("fill here")
match expression {
Expression::Num(value) => Ok(*value),
Expression::Variable(name) => self
.variables
.get(name)
.copied()
.ok_or(anyhow!("Unknown variable")),
Expression::BinOp { op, lhs, rhs } => {
let lhs = self.calc_expression(lhs)?;
let rhs = self.calc_expression(rhs)?;
match op {
BinOp::Add => Ok(lhs + rhs),
BinOp::Subtract => Ok(lhs - rhs),
BinOp::Multiply => Ok(lhs * rhs),
BinOp::Divide if rhs == 0.0 => Err(anyhow!("Division by zero")),
BinOp::Divide => Ok(lhs / rhs),
BinOp::Power => Ok(lhs.powf(rhs)),
}
}
}
}
/// Calculates the given command. (We assume the absence of overflow.)
@@ -43,6 +62,14 @@ impl Context {
///
/// After calculating commad `3 ^ 2` => Context's variables = `{($0,8),(v,1),($1,9)}`
pub fn calc_command(&mut self, command: &Command) -> Result<(String, f64)> {
todo!("fill here")
let value = self.calc_expression(&command.expression)?;
let name = command.variable.clone().unwrap_or_else(|| {
let name = format!("${}", self.anonymous_counter);
self.anonymous_counter += 1;
name
});
_ = self.variables.insert(name.clone(), value);
Ok((name, value))
}
}

View File

@@ -14,11 +14,19 @@ use super::syntax::*;
#[allow(missing_docs)]
#[allow(missing_debug_implementations)]
mod inner {
use pest::pratt_parser::{Assoc::*, *};
use pest_derive::*;
#[derive(Parser)]
#[grammar = "assignments/assignment04/syntax.pest"]
pub(crate) struct SyntaxParser;
lazy_static::lazy_static! {
pub static ref PRATT_PARSER: PrattParser<Rule> = PrattParser::new()
.op(Op::infix(Rule::add, Left) | Op::infix(Rule::subtract, Left))
.op(Op::infix(Rule::multiply, Left) | Op::infix(Rule::divide, Left))
.op(Op::infix(Rule::power, Right));
}
}
use inner::*;
@@ -32,5 +40,51 @@ use inner::*;
/// e.g. `1+2+3` should be parsed into `(1+2)+3`, not `1+(2+3)` because the associativity of
/// plus("add" in our hw) operator is `Left`.
pub fn parse_command(line: &str) -> Result<Command> {
todo!("fill here")
let mut variable: Option<&str> = None;
let mut expression: Option<Expression> = None;
for pair in SyntaxParser::parse(Rule::command, line)? {
match pair.as_rule() {
Rule::var => variable = Some(pair.as_str()),
Rule::expr => expression = Some(parse_expression(pair.into_inner())?),
Rule::EOI => {}
_ => unreachable!(),
}
}
Ok(Command {
variable: variable.map(|s| s.to_string()),
expression: expression.unwrap(),
})
}
/// Parses expression.
pub fn parse_expression(pairs: Pairs<'_, Rule>) -> Result<Expression> {
let mut first_term: Option<Expression> = None;
let mut operation: Option<BinOp> = None;
let mut second_term: Option<Expression> = None;
PRATT_PARSER
.map_primary(|primary| match primary.as_rule() {
Rule::num => Ok(Expression::Num(primary.as_str().parse()?)),
Rule::var => Ok(Expression::Variable(primary.as_str().to_string())),
Rule::expr => Ok(parse_expression(primary.into_inner())?),
_ => unreachable!(),
})
.map_infix(|lhs, op, rhs| {
let op = match op.as_rule() {
Rule::add => BinOp::Add,
Rule::subtract => BinOp::Subtract,
Rule::multiply => BinOp::Multiply,
Rule::divide => BinOp::Divide,
Rule::power => BinOp::Power,
_ => unreachable!(),
};
Ok(Expression::BinOp {
op,
lhs: Box::new(lhs?),
rhs: Box::new(rhs?),
})
})
.parse(pairs)
}