|  | @@ -37,55 +37,52 @@ impl<'a> Compiler<'a> {
 | 
	
		
			
				|  |  |          &mut self,
 | 
	
		
			
				|  |  |          expr: &'a Expr,
 | 
	
		
			
				|  |  |          exit_label: Addr,
 | 
	
		
			
				|  |  | -    ) -> Result<(Vec<OpCode>, Register), Error> {
 | 
	
		
			
				|  |  | -        let mut return_value = self.next_register();
 | 
	
		
			
				|  |  | +        return_to: Register,
 | 
	
		
			
				|  |  | +    ) -> Result<Vec<OpCode>, Error> {
 | 
	
		
			
				|  |  |          Ok(match expr {
 | 
	
		
			
				|  |  | -            Expr::Variable(name) => (
 | 
	
		
			
				|  |  | -                vec![OpCode::LOAD_EXTERNAL(return_value, name.clone())],
 | 
	
		
			
				|  |  | -                return_value,
 | 
	
		
			
				|  |  | -            ),
 | 
	
		
			
				|  |  | -            Expr::Bool(value) => (
 | 
	
		
			
				|  |  | -                vec![OpCode::LOAD(return_value, Value::Bool(*value))],
 | 
	
		
			
				|  |  | -                return_value,
 | 
	
		
			
				|  |  | -            ),
 | 
	
		
			
				|  |  | -            Expr::String(string) => (
 | 
	
		
			
				|  |  | -                vec![OpCode::LOAD(return_value, Value::String(string.clone()))],
 | 
	
		
			
				|  |  | -                return_value,
 | 
	
		
			
				|  |  | -            ),
 | 
	
		
			
				|  |  | -            Expr::Number(number) => (
 | 
	
		
			
				|  |  | -                vec![OpCode::LOAD(return_value, Value::Number(*number))],
 | 
	
		
			
				|  |  | -                return_value,
 | 
	
		
			
				|  |  | -            ),
 | 
	
		
			
				|  |  | +            Expr::Variable(name) => vec![OpCode::LOAD_EXTERNAL(return_to, name.clone())],
 | 
	
		
			
				|  |  | +            Expr::Bool(value) => vec![OpCode::LOAD(return_to, Value::Bool(*value))],
 | 
	
		
			
				|  |  | +            Expr::String(string) => vec![OpCode::LOAD(return_to, Value::String(string.clone()))],
 | 
	
		
			
				|  |  | +            Expr::Number(number) => vec![OpCode::LOAD(return_to, Value::Number(*number))],
 | 
	
		
			
				|  |  |              Expr::Op { op, terms } => {
 | 
	
		
			
				|  |  |                  let mut opcodes = vec![];
 | 
	
		
			
				|  |  |                  let current_exit_label = self.next_label();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                let mut compiled_terms = terms
 | 
	
		
			
				|  |  | -                    .iter()
 | 
	
		
			
				|  |  | -                    .map(|term| self.compile_expr(term, current_exit_label))
 | 
	
		
			
				|  |  | -                    .collect::<Result<Vec<_>, _>>()?;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |                  match op {
 | 
	
		
			
				|  |  |                      ExprOp::Not => {
 | 
	
		
			
				|  |  | -                        let (mut opcodes, term_return_value) =
 | 
	
		
			
				|  |  | -                            compiled_terms.pop().ok_or(Error::UnexpectedExprState)?;
 | 
	
		
			
				|  |  | -                        if !compiled_terms.is_empty() {
 | 
	
		
			
				|  |  | +                        if terms.len() != 1 {
 | 
	
		
			
				|  |  |                              return Err(Error::UnexpectedExprState);
 | 
	
		
			
				|  |  |                          }
 | 
	
		
			
				|  |  | -                        opcodes.push(OpCode::NOT(return_value, return_value));
 | 
	
		
			
				|  |  | -                        return_value = term_return_value;
 | 
	
		
			
				|  |  | +                        let mut opcodes = terms
 | 
	
		
			
				|  |  | +                            .first()
 | 
	
		
			
				|  |  | +                            .map(|expr| self.compile_expr(expr, exit_label, return_to))
 | 
	
		
			
				|  |  | +                            .ok_or(Error::UnexpectedExprState)??;
 | 
	
		
			
				|  |  | +                        opcodes.push(OpCode::NOT(return_to, return_to));
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                      ExprOp::Eq => {
 | 
	
		
			
				|  |  | -                        let mut iter = compiled_terms.into_iter();
 | 
	
		
			
				|  |  | -                        let (mut term_opcodes, last_value) =
 | 
	
		
			
				|  |  | -                            iter.next().ok_or(Error::MissingNextRule)?;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +                        let first = self.next_register();
 | 
	
		
			
				|  |  | +                        let other = self.next_register();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        let terms = terms
 | 
	
		
			
				|  |  | +                            .iter()
 | 
	
		
			
				|  |  | +                            .enumerate()
 | 
	
		
			
				|  |  | +                            .map(|(idx, term)| {
 | 
	
		
			
				|  |  | +                                self.compile_expr(
 | 
	
		
			
				|  |  | +                                    term,
 | 
	
		
			
				|  |  | +                                    current_exit_label,
 | 
	
		
			
				|  |  | +                                    if idx == 0 { first } else { other },
 | 
	
		
			
				|  |  | +                                )
 | 
	
		
			
				|  |  | +                            })
 | 
	
		
			
				|  |  | +                            .collect::<Result<Vec<_>, _>>()?;
 | 
	
		
			
				|  |  | +                        let mut iter = terms.into_iter();
 | 
	
		
			
				|  |  | +                        let mut term_opcodes = iter.next().ok_or(Error::MissingNextRule)?;
 | 
	
		
			
				|  |  |                          opcodes.append(&mut term_opcodes);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |                          if iter
 | 
	
		
			
				|  |  | -                            .map(|(mut term_codes, term_return)| {
 | 
	
		
			
				|  |  | +                            .map(|mut term_codes| {
 | 
	
		
			
				|  |  |                                  opcodes.append(&mut term_codes);
 | 
	
		
			
				|  |  | -                                opcodes.push(OpCode::EQ(return_value, last_value, term_return));
 | 
	
		
			
				|  |  | -                                opcodes.push(OpCode::JNE(return_value, exit_label));
 | 
	
		
			
				|  |  | +                                opcodes.push(OpCode::EQ(return_to, first, other));
 | 
	
		
			
				|  |  | +                                opcodes.push(OpCode::JNE(return_to, exit_label));
 | 
	
		
			
				|  |  |                                  1
 | 
	
		
			
				|  |  |                              })
 | 
	
		
			
				|  |  |                              .sum::<usize>()
 | 
	
	
		
			
				|  | @@ -97,32 +94,51 @@ impl<'a> Compiler<'a> {
 | 
	
		
			
				|  |  |                          let _ = opcodes.pop();
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                      ExprOp::Add | ExprOp::Mul | ExprOp::Div | ExprOp::Sub => {
 | 
	
		
			
				|  |  | -                        let mut iter = compiled_terms.into_iter();
 | 
	
		
			
				|  |  | -                        let (mut term_opcodes, return_value) =
 | 
	
		
			
				|  |  | -                            iter.next().ok_or(Error::MissingNextRule)?;
 | 
	
		
			
				|  |  | +                        let term_return = self.next_register();
 | 
	
		
			
				|  |  | +                        let terms = terms
 | 
	
		
			
				|  |  | +                            .iter()
 | 
	
		
			
				|  |  | +                            .enumerate()
 | 
	
		
			
				|  |  | +                            .map(|(idx, term)| {
 | 
	
		
			
				|  |  | +                                self.compile_expr(term, current_exit_label, term_return)
 | 
	
		
			
				|  |  | +                            })
 | 
	
		
			
				|  |  | +                            .collect::<Result<Vec<_>, _>>()?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        let mut iter = terms.into_iter();
 | 
	
		
			
				|  |  | +                        let mut term_opcodes = iter.next().ok_or(Error::MissingNextRule)?;
 | 
	
		
			
				|  |  |                          opcodes.append(&mut term_opcodes);
 | 
	
		
			
				|  |  | +                        opcodes.push(OpCode::MOV(return_to, term_return));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                        for (mut term_opcodes, term_return) in iter {
 | 
	
		
			
				|  |  | +                        for mut term_opcodes in iter {
 | 
	
		
			
				|  |  |                              opcodes.append(&mut term_opcodes);
 | 
	
		
			
				|  |  |                              opcodes.push(match op {
 | 
	
		
			
				|  |  | -                                ExprOp::Add => OpCode::ADD(return_value, return_value, term_return),
 | 
	
		
			
				|  |  | -                                ExprOp::Mul => OpCode::MUL(return_value, return_value, term_return),
 | 
	
		
			
				|  |  | -                                ExprOp::Div => OpCode::DIV(return_value, return_value, term_return),
 | 
	
		
			
				|  |  | -                                ExprOp::Sub => OpCode::SUB(return_value, return_value, term_return),
 | 
	
		
			
				|  |  | +                                ExprOp::Add => OpCode::ADD(return_to, return_to, term_return),
 | 
	
		
			
				|  |  | +                                ExprOp::Mul => OpCode::MUL(return_to, return_to, term_return),
 | 
	
		
			
				|  |  | +                                ExprOp::Div => OpCode::DIV(return_to, return_to, term_return),
 | 
	
		
			
				|  |  | +                                ExprOp::Sub => OpCode::SUB(return_to, return_to, term_return),
 | 
	
		
			
				|  |  |                                  _ => unreachable!(),
 | 
	
		
			
				|  |  |                              });
 | 
	
		
			
				|  |  |                          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                        return Ok((opcodes, return_value));
 | 
	
		
			
				|  |  | +                        return Ok(opcodes);
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                      ExprOp::Or | ExprOp::And => {
 | 
	
		
			
				|  |  | -                        opcodes = vec![OpCode::LOAD(return_value, Value::Bool(false))];
 | 
	
		
			
				|  |  | -                        for (mut term_opcodes, term_return_value) in compiled_terms.into_iter() {
 | 
	
		
			
				|  |  | +                        opcodes = vec![OpCode::LOAD(return_to, Value::Bool(false))];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        let terms = terms
 | 
	
		
			
				|  |  | +                            .iter()
 | 
	
		
			
				|  |  | +                            .enumerate()
 | 
	
		
			
				|  |  | +                            .map(|(idx, term)| {
 | 
	
		
			
				|  |  | +                                self.compile_expr(term, current_exit_label, return_to)
 | 
	
		
			
				|  |  | +                            })
 | 
	
		
			
				|  |  | +                            .collect::<Result<Vec<_>, _>>()?;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        let mut iter = terms.into_iter();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        for mut term_opcodes in iter.into_iter() {
 | 
	
		
			
				|  |  |                              opcodes.append(&mut term_opcodes);
 | 
	
		
			
				|  |  | -                            opcodes.push(OpCode::MOV(return_value, term_return_value));
 | 
	
		
			
				|  |  |                              match op {
 | 
	
		
			
				|  |  | -                                ExprOp::Or => opcodes.push(OpCode::JEQ(return_value, exit_label)),
 | 
	
		
			
				|  |  | -                                ExprOp::And => opcodes.push(OpCode::JNE(return_value, exit_label)),
 | 
	
		
			
				|  |  | +                                ExprOp::Or => opcodes.push(OpCode::JEQ(return_to, exit_label)),
 | 
	
		
			
				|  |  | +                                ExprOp::And => opcodes.push(OpCode::JNE(return_to, exit_label)),
 | 
	
		
			
				|  |  |                                  _ => unreachable!(),
 | 
	
		
			
				|  |  |                              };
 | 
	
		
			
				|  |  |                          }
 | 
	
	
		
			
				|  | @@ -131,20 +147,20 @@ impl<'a> Compiler<'a> {
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  opcodes.push(OpCode::LABEL(current_exit_label));
 | 
	
		
			
				|  |  | -                (opcodes, return_value)
 | 
	
		
			
				|  |  | +                opcodes
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  |          })
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn optimize(opcodes: Vec<OpCode>) -> (Vec<OpCode>, bool) {
 | 
	
		
			
				|  |  |          vec![
 | 
	
		
			
				|  |  | -            optimizations::assign_unique_register_addresses,
 | 
	
		
			
				|  |  | +            //optimizations::assign_unique_register_addresses,
 | 
	
		
			
				|  |  |              optimizations::remove_redundant_load_and_mov,
 | 
	
		
			
				|  |  |              optimizations::remove_unused_values,
 | 
	
		
			
				|  |  |              optimizations::calculate_static_values,
 | 
	
		
			
				|  |  |              optimizations::remove_useless_jumps,
 | 
	
		
			
				|  |  |              optimizations::remove_dead_code,
 | 
	
		
			
				|  |  | -            optimizations::move_load_top,
 | 
	
		
			
				|  |  | +            //optimizations::move_load_top,
 | 
	
		
			
				|  |  |          ]
 | 
	
		
			
				|  |  |          .into_iter()
 | 
	
		
			
				|  |  |          .fold((opcodes, false), |(opcodes, has_optimized), f| {
 | 
	
	
		
			
				|  | @@ -211,9 +227,10 @@ impl<'a> Compiler<'a> {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      pub fn compile(mut self) -> Result<Vec<OpCode>, Error> {
 | 
	
		
			
				|  |  |          let program_exit = self.next_label();
 | 
	
		
			
				|  |  | -        let (mut opcodes, return_value) = self.compile_expr(self.expr, program_exit)?;
 | 
	
		
			
				|  |  | +        let return_to = self.next_register();
 | 
	
		
			
				|  |  | +        let mut opcodes = self.compile_expr(self.expr, program_exit, return_to)?;
 | 
	
		
			
				|  |  |          opcodes.push(OpCode::LABEL(program_exit));
 | 
	
		
			
				|  |  | -        opcodes.push(OpCode::HLT(return_value));
 | 
	
		
			
				|  |  | +        opcodes.push(OpCode::HLT(return_to));
 | 
	
		
			
				|  |  |          Ok(opcodes)
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 |