Cesar Rodas 9 月之前
父節點
當前提交
7befdbc554
共有 3 個文件被更改,包括 99 次插入55 次删除
  1. 3 0
      utxo/src/filter_expr/mod.rs
  2. 7 8
      utxo/src/filter_expr/parser.rs
  3. 89 47
      utxo/src/filter_expr/program.rs

+ 3 - 0
utxo/src/filter_expr/mod.rs

@@ -46,6 +46,9 @@ pub enum Error {
 
     #[error("Unknown label: {0}")]
     UnknownLabel(usize),
+
+    #[error("Unexpected expression state")]
+    UnexpectedExprState,
 }
 
 use std::num::ParseIntError;

+ 7 - 8
utxo/src/filter_expr/parser.rs

@@ -88,8 +88,7 @@ fn parse_expr(pair: pest::iterators::Pair<Rule>) -> Result<Expr, Error> {
                     let second_expr = parse_expr(second)?;
                     Expr::Op {
                         op,
-                        left: Box::new(first_expr),
-                        right: Box::new(second_expr),
+                        terms: vec![Box::new(first_expr), Box::new(second_expr)],
                     }
                 } else {
                     first_expr
@@ -112,12 +111,12 @@ fn parse_expr(pair: pest::iterators::Pair<Rule>) -> Result<Expr, Error> {
         }
         Rule::not_expr => {
             let mut inner = pair.into_inner();
-            Expr::Not(Box::new(
-                inner
-                    .next()
-                    .map(parse_expr)
-                    .ok_or(Error::MissingNextRule)??,
-            ))
+            Expr::Op {
+                op: ExprOp::Not,
+                terms: vec![Box::new(parse_expr(
+                    inner.next().ok_or(Error::MissingNextRule)?,
+                )?)],
+            }
         }
         Rule::variable => {
             let mut inner = pair.into_inner();

+ 89 - 47
utxo/src/filter_expr/program.rs

@@ -50,9 +50,13 @@ impl<'a> Compiler<'a> {
         self.current_register
     }
 
-    fn compile_expr(&mut self, expr: &'a Expr, exit_label: Addr) -> (Vec<OpCode>, usize) {
-        let return_value = self.next_register();
-        match expr {
+    fn compile_expr(
+        &mut self,
+        expr: &'a Expr,
+        exit_label: Addr,
+    ) -> Result<(Vec<OpCode>, usize), Error> {
+        let mut return_value = self.next_register();
+        Ok(match expr {
             Expr::Variable(name) => (
                 vec![OpCode::LOAD_EXTERNAL(return_value, name.into())],
                 return_value,
@@ -65,56 +69,82 @@ impl<'a> Compiler<'a> {
                 vec![OpCode::LOAD(return_value, Value::Number(*number))],
                 return_value,
             ),
-            Expr::Not(expr) => {
-                let (mut expr, prev_return_value) = self.compile_expr(expr, exit_label);
-                expr.push(OpCode::NOT(return_value, prev_return_value));
-                (expr, return_value)
-            }
-            Expr::Op { op, left, right } => {
-                let mut to_return = vec![];
+            Expr::Op { op, terms } => {
+                let mut opcodes = vec![];
                 let current_exit_label = self.next_label();
-                let (mut left, return_left) = self.compile_expr(left, current_exit_label);
-                let (mut right, return_right) = self.compile_expr(right, current_exit_label);
 
-                to_return.append(&mut left.clone());
-                to_return.append(&mut right.clone());
+                let mut compiled_terms = terms
+                    .iter()
+                    .map(|term| self.compile_expr(term, current_exit_label))
+                    .collect::<Result<Vec<_>, _>>()?;
 
                 match op {
-                    ExprOp::Eq => {
-                        to_return.push(OpCode::EQ(return_value, return_left, return_right));
-                    }
-                    ExprOp::Add => {
-                        to_return.push(OpCode::ADD(return_value, return_left, return_right))
-                    }
-                    ExprOp::Or => {
-                        to_return = vec![OpCode::LOAD(return_value, Value::Bool(false))];
-                        to_return.append(&mut left);
-                        to_return.push(OpCode::MOV(return_value, return_left));
-                        to_return.push(OpCode::JEQ(return_value, exit_label));
-                        to_return.append(&mut right);
-                        to_return.push(OpCode::OR(return_value, return_left, return_right))
+                    ExprOp::Not => {
+                        let (mut opcodes, term_return_value) =
+                            compiled_terms.pop().ok_or(Error::EmptyRegisters)?;
+                        if !compiled_terms.is_empty() {
+                            return Err(Error::UnexpectedExprState);
+                        }
+                        opcodes.push(OpCode::NOT(return_value, return_value));
+                        return_value = term_return_value;
                     }
-                    ExprOp::And => {
-                        to_return = vec![OpCode::LOAD(return_value, Value::Bool(false))];
-                        to_return.append(&mut left);
-                        to_return.push(OpCode::MOV(return_value, return_left));
-                        to_return.push(OpCode::JNE(return_value, exit_label));
-                        to_return.append(&mut right);
-                        to_return.push(OpCode::AND(return_value, return_left, return_right))
+                    ExprOp::Eq => {
+                        let cmp = self.next_register();
+                        let last_value = self.next_register();
+                        let mut iter = compiled_terms.into_iter();
+                        let (mut term_opcodes, return_from_expr) =
+                            iter.next().ok_or(Error::MissingNextRule)?;
+
+                        opcodes.append(&mut term_opcodes);
+                        opcodes.push(OpCode::MOV(last_value, return_from_expr));
+
+                        for (mut term_opcodes, term_return) in iter {
+                            opcodes.append(&mut term_opcodes);
+                            opcodes.push(OpCode::EQ(cmp, last_value, term_return));
+                            opcodes.push(OpCode::JNE(exit_label, cmp));
+                            opcodes.push(OpCode::MOV(last_value, term_return));
+                        }
+
+                        opcodes.push(OpCode::LOAD(return_value, true.into()));
                     }
-                    ExprOp::Mul => {
-                        to_return.push(OpCode::MUL(return_value, return_left, return_right))
+                    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)?;
+                        opcodes.append(&mut term_opcodes);
+
+                        for (mut term_opcodes, term_return) 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),
+                                _ => unreachable!(),
+                            });
+                        }
+
+                        return Ok((opcodes, return_value));
                     }
-                    ExprOp::Sub => {
-                        to_return.push(OpCode::SUB(return_value, return_left, return_right))
+                    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.append(&mut term_opcodes);
+                            opcodes.push(OpCode::MOV(return_value, term_return_value));
+                            match op {
+                                ExprOp::Or => opcodes.push(OpCode::JEQ(exit_label, return_value)),
+                                ExprOp::And => opcodes.push(OpCode::JNE(exit_label, return_value)),
+                                _ => unreachable!(),
+                            };
+                        }
                     }
                     x => panic!("unimplemented {:#?}", x),
                 }
 
-                to_return.push(OpCode::LABEL(current_exit_label));
-                (to_return, return_value)
+                opcodes.push(OpCode::LABEL(current_exit_label));
+                (opcodes, return_value)
             }
-        }
+        })
     }
 
     fn resolve_label_to_addr(opcodes: Vec<OpCode>) -> Result<Vec<OpCode>, Error> {
@@ -156,12 +186,12 @@ impl<'a> Compiler<'a> {
             .collect()
     }
 
-    pub fn compile(mut self) -> Vec<OpCode> {
-        let exit_point = self.next_label();
-        let (mut opcodes, return_value) = self.compile_expr(self.expr, exit_point);
-        opcodes.push(OpCode::LABEL(exit_point));
+    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)?;
+        opcodes.push(OpCode::LABEL(program_exit));
         opcodes.push(OpCode::HLT(return_value));
-        opcodes
+        Ok(opcodes)
     }
 }
 
@@ -170,8 +200,20 @@ impl Program {
         let ast = parse_query(code)?;
 
         let opcodes = ast.where_clause.map_or_else(
-            || vec![OpCode::LOAD(0, true.into()), OpCode::HLT(0)],
+            || Ok(vec![OpCode::LOAD(0, true.into()), OpCode::HLT(0)]),
             |expr| Compiler::new(&expr).compile(),
+        )?;
+
+        println!(
+            "{}",
+            opcodes
+                .iter()
+                .map(|x| match x {
+                    OpCode::HLT(_) | OpCode::LABEL(_) => x.to_string(),
+                    x => format!("\t{}", x.to_string()),
+                })
+                .collect::<Vec<_>>()
+                .join("\n")
         );
 
         Ok(Self {