Просмотр исходного кода

wallet/expr: allow adding consts to the compiler so we can avoid using format!() macros for consts

darkfi 1 год назад
Родитель
Сommit
a2a88d0a74
3 измененных файлов с 129 добавлено и 79 удалено
  1. 25 17
      bin/darkwallet/src/app/schema.rs
  2. 103 61
      bin/darkwallet/src/expr/compile.rs
  3. 1 1
      bin/darkwallet/src/expr/mod.rs

+ 25 - 17
bin/darkwallet/src/app/schema.rs

@@ -21,7 +21,7 @@ use sled_overlay::sled;
 use crate::{
     darkirc::{DarkIrcBackendPtr, Privmsg},
     error::Error,
-    expr,
+    expr::Compiler,
     gfx::{GraphicsEventPublisherPtr, Rectangle, RenderApiPtr, Vertex},
     mesh::{Color, MeshBuilder},
     prop::{Property, PropertyBool, PropertyStr, PropertySubType, PropertyType, Role},
@@ -83,6 +83,8 @@ const FONTSIZE: f32 = 40.;
 const FONTSIZE: f32 = 20.;
 
 pub(super) async fn make_old(app: &App) {
+    let mut cc = Compiler::new();
+
     //let mut tasks = vec![];
     // Create a layer called view
     let mut sg = app.sg.lock().await;
@@ -145,7 +147,7 @@ pub(super) async fn make_old(app: &App) {
 
     let node = sg.get_node_mut(node_id).unwrap();
     let prop = node.get_property("rect").unwrap();
-    let code = expr::compile("w - 220").unwrap();
+    let code = cc.compile("w - 220").unwrap();
     prop.set_expr(Role::App, 0, code).unwrap();
     prop.set_f32(Role::App, 1, 10.).unwrap();
     prop.set_f32(Role::App, 2, 200.).unwrap();
@@ -185,7 +187,7 @@ pub(super) async fn make_old(app: &App) {
     let node = sg.get_node_mut(node_id).unwrap();
     node.set_property_bool(Role::App, "is_active", true).unwrap();
     let prop = node.get_property("rect").unwrap();
-    let code = expr::compile("w - 220").unwrap();
+    let code = cc.compile("w - 220").unwrap();
     prop.set_expr(Role::App, 0, code).unwrap();
     prop.set_f32(Role::App, 1, 10.).unwrap();
     prop.set_f32(Role::App, 2, 200.).unwrap();
@@ -247,10 +249,10 @@ pub(super) async fn make_old(app: &App) {
     let node = sg.get_node_mut(node_id).unwrap();
     let prop = node.get_property("rect").unwrap();
     prop.set_f32(Role::App, 0, 0.).unwrap();
-    let code = expr::compile("h/2").unwrap();
+    let code = cc.compile("h/2").unwrap();
     prop.set_expr(Role::App, 1, code).unwrap();
     prop.set_expr(Role::App, 2, shape::load_var("w")).unwrap();
-    let code = expr::compile("h/2 - 200").unwrap();
+    let code = cc.compile("h/2 - 200").unwrap();
     prop.set_expr(Role::App, 3, code).unwrap();
 
     node.set_property_u32(Role::App, "z_index", 2).unwrap();
@@ -266,7 +268,7 @@ pub(super) async fn make_old(app: &App) {
     );
     shape.add_filled_box(
         shape::const_f32(0.),
-        expr::compile("h - 5").unwrap(),
+        cc.compile("h - 5").unwrap(),
         shape::load_var("w"),
         shape::load_var("h"),
         [0., 1., 0., 1.],
@@ -435,10 +437,10 @@ pub(super) async fn make_old(app: &App) {
     let node = sg.get_node(node_id).unwrap();
     let prop = node.get_property("rect").unwrap();
     prop.set_f32(Role::App, 0, 0.).unwrap();
-    let code = expr::compile("h/2").unwrap();
+    let code = cc.compile("h/2").unwrap();
     prop.set_expr(Role::App, 1, code).unwrap();
     prop.set_expr(Role::App, 2, shape::load_var("w")).unwrap();
-    let code = expr::compile("h/2 - 200").unwrap();
+    let code = cc.compile("h/2 - 200").unwrap();
     prop.set_expr(Role::App, 3, code).unwrap();
     node.set_property_f32(Role::App, "font_size", 20.).unwrap();
     node.set_property_f32(Role::App, "line_height", 30.).unwrap();
@@ -530,6 +532,12 @@ pub(super) async fn make_old(app: &App) {
 }
 
 pub(super) async fn make(app: &App) {
+    let mut cc = Compiler::new();
+
+    cc.add_const_f32("EDITCHAT_HEIGHT", EDITCHAT_HEIGHT);
+    cc.add_const_f32("SENDLABEL_WIDTH", SENDLABEL_WIDTH);
+    cc.add_const_f32("SENDLABEL_LHS_PAD", SENDLABEL_LHS_PAD);
+
     // Main view
     let mut sg = app.sg.lock().await;
     let layer_node_id = create_layer(&mut sg, "view");
@@ -654,7 +662,7 @@ pub(super) async fn make(app: &App) {
     prop.set_f32(Role::App, 0, 0.).unwrap();
     prop.set_f32(Role::App, 1, EDITCHAT_HEIGHT).unwrap();
     prop.set_expr(Role::App, 2, shape::load_var("w")).unwrap();
-    let code = expr::compile(format!("h - 2 * {EDITCHAT_HEIGHT}")).unwrap();
+    let code = cc.compile("h - 2 * EDITCHAT_HEIGHT").unwrap();
     prop.set_expr(Role::App, 3, code).unwrap();
     node.set_property_f32(Role::App, "font_size", FONTSIZE).unwrap();
     node.set_property_f32(Role::App, "line_height", FONTSIZE * 1.6).unwrap();
@@ -748,7 +756,7 @@ pub(super) async fn make(app: &App) {
     let node = sg.get_node_mut(node_id).unwrap();
     let prop = node.get_property("rect").unwrap();
     prop.set_f32(Role::App, 0, 0.).unwrap();
-    let code = expr::compile(format!("h - {EDITCHAT_HEIGHT}")).unwrap();
+    let code = cc.compile("h - EDITCHAT_HEIGHT").unwrap();
     prop.set_expr(Role::App, 1, code).unwrap();
     prop.set_expr(Role::App, 2, shape::load_var("w")).unwrap();
     prop.set_f32(Role::App, 3, EDITCHAT_HEIGHT).unwrap();
@@ -758,14 +766,14 @@ pub(super) async fn make(app: &App) {
     shape.add_filled_box(
         shape::const_f32(0.),
         shape::const_f32(0.),
-        expr::compile(format!("w - {SENDLABEL_WIDTH}")).unwrap(),
+        cc.compile("w - SENDLABEL_WIDTH").unwrap(),
         shape::load_var("h"),
         [0., 0.13, 0.08, 1.],
     );
     shape.add_filled_box(
-        expr::compile(format!("w - {SENDLABEL_WIDTH}")).unwrap(),
+        cc.compile("w - SENDLABEL_WIDTH").unwrap(),
         shape::const_f32(0.),
-        expr::compile(format!("w - {SENDLABEL_WIDTH} - 1")).unwrap(),
+        cc.compile("w - SENDLABEL_WIDTH - 1").unwrap(),
         shape::load_var("h"),
         [0.4, 0.4, 0.4, 1.],
     );
@@ -792,9 +800,9 @@ pub(super) async fn make(app: &App) {
 
     let node = sg.get_node_mut(node_id).unwrap();
     let prop = node.get_property("rect").unwrap();
-    let code = expr::compile(format!("w - {}", SENDLABEL_WIDTH - SENDLABEL_LHS_PAD)).unwrap();
+    let code = cc.compile("w - (SENDLABEL_WIDTH - SENDLABEL_LHS_PAD)").unwrap();
     prop.set_expr(Role::App, 0, code).unwrap();
-    let code = expr::compile(format!("h - {EDITCHAT_HEIGHT}")).unwrap();
+    let code = cc.compile("h - EDITCHAT_HEIGHT").unwrap();
     prop.set_expr(Role::App, 1, code).unwrap();
     prop.set_f32(Role::App, 2, SENDLABEL_WIDTH).unwrap();
     prop.set_f32(Role::App, 3, EDITCHAT_HEIGHT).unwrap();
@@ -830,9 +838,9 @@ pub(super) async fn make(app: &App) {
 
     let prop = node.get_property("rect").unwrap();
     prop.set_f32(Role::App, 0, EDITCHAT_LHS_PAD).unwrap();
-    let code = expr::compile(format!("h - {EDITCHAT_HEIGHT}")).unwrap();
+    let code = cc.compile("h - EDITCHAT_HEIGHT").unwrap();
     prop.set_expr(Role::App, 1, code).unwrap();
-    let code = expr::compile(format!("w - ({SENDLABEL_WIDTH} + 20)")).unwrap();
+    let code = cc.compile("w - (SENDLABEL_WIDTH + 20)").unwrap();
     prop.set_expr(Role::App, 2, code).unwrap();
     prop.set_f32(Role::App, 3, EDITCHAT_HEIGHT).unwrap();
 

+ 103 - 61
bin/darkwallet/src/expr/compile.rs

@@ -20,6 +20,7 @@ use crate::{
     error::{Error, Result},
     //prop::{Property, PropertySubType, PropertyType, PropertySExprValue},
 };
+use std::collections::HashMap;
 
 use super::{Op, SExprCode};
 
@@ -27,15 +28,6 @@ fn remove_whitespace(s: &str) -> String {
     s.chars().filter(|c| !c.is_whitespace()).collect()
 }
 
-pub fn compile<S: AsRef<str>>(stmts: S) -> Result<SExprCode> {
-    let stmts = stmts.as_ref();
-    let mut code = vec![];
-    for stmt in stmts.split(';') {
-        code.push(compile_line(stmt)?);
-    }
-    Ok(code)
-}
-
 #[derive(Debug, Clone)]
 enum Token {
     LoadVar(String),
@@ -61,52 +53,99 @@ impl Token {
     }
 }
 
-fn tokenize(stmt: &str) -> Vec<Token> {
-    let mut tokens = Vec::new();
-    let mut current_token = String::new();
-    for chr in stmt.chars() {
-        match chr {
-            '+' => {
-                clear_accum(&mut current_token, &mut tokens);
-                tokens.push(Token::Add);
-            }
-            '-' => {
-                clear_accum(&mut current_token, &mut tokens);
-                tokens.push(Token::Sub);
-            }
-            '*' => {
-                clear_accum(&mut current_token, &mut tokens);
-                tokens.push(Token::Mul);
-            }
-            '/' => {
-                clear_accum(&mut current_token, &mut tokens);
-                tokens.push(Token::Div);
-            }
-            '(' => {
-                clear_accum(&mut current_token, &mut tokens);
-                tokens.push(Token::LeftParen);
-            }
-            ')' => {
-                clear_accum(&mut current_token, &mut tokens);
-                tokens.push(Token::RightParen);
-            }
-            _ => current_token.push(chr),
+pub struct Compiler {
+    table: HashMap<String, Token>,
+}
+
+impl Compiler {
+    pub fn new() -> Self {
+        Self { table: HashMap::new() }
+    }
+
+    pub fn add_const_f32<S: Into<String>>(&mut self, name: S, val: f32) {
+        self.table.insert(name.into(), Token::ConstFloat32(val));
+    }
+    /*
+    pub fn get_const_f32<S: AsRef<str>>(&self, name: S) -> Option<f32> {
+        let name = name.as_ref();
+        let val = self.table.get(name)?;
+        match val {
+            Token::ConstFloat32(v) => Some(v)
+            _ => None
         }
     }
-    clear_accum(&mut current_token, &mut tokens);
-    tokens
-}
+    */
 
-fn clear_accum(current_token: &mut String, tokens: &mut Vec<Token>) {
-    let prev_token = std::mem::replace(current_token, String::new());
-    if prev_token.is_empty() {
-        return
+    pub fn compile<S: AsRef<str>>(&self, stmts: S) -> Result<SExprCode> {
+        let stmts = stmts.as_ref();
+        let mut code = vec![];
+        for stmt in stmts.split(';') {
+            code.push(self.compile_line(stmt)?);
+        }
+        Ok(code)
     }
 
-    // Number or var?
-    match prev_token.parse::<f32>() {
-        Ok(v) => tokens.push(Token::ConstFloat32(v)),
-        Err(_) => tokens.push(Token::LoadVar(prev_token)),
+    fn compile_line(&self, stmt: &str) -> Result<Op> {
+        let stmt = remove_whitespace(stmt);
+        let tokens = self.tokenize(&stmt);
+        //println!("{tokens:#?}");
+        let tokens = to_rpn(tokens)?;
+        //println!("{tokens:#?}");
+        Ok(convert(&mut tokens.into_iter())?)
+    }
+
+    fn tokenize(&self, stmt: &str) -> Vec<Token> {
+        let mut tokens = Vec::new();
+        let mut current_token = String::new();
+        for chr in stmt.chars() {
+            match chr {
+                '+' => {
+                    self.clear_accum(&mut current_token, &mut tokens);
+                    tokens.push(Token::Add);
+                }
+                '-' => {
+                    self.clear_accum(&mut current_token, &mut tokens);
+                    tokens.push(Token::Sub);
+                }
+                '*' => {
+                    self.clear_accum(&mut current_token, &mut tokens);
+                    tokens.push(Token::Mul);
+                }
+                '/' => {
+                    self.clear_accum(&mut current_token, &mut tokens);
+                    tokens.push(Token::Div);
+                }
+                '(' => {
+                    self.clear_accum(&mut current_token, &mut tokens);
+                    tokens.push(Token::LeftParen);
+                }
+                ')' => {
+                    self.clear_accum(&mut current_token, &mut tokens);
+                    tokens.push(Token::RightParen);
+                }
+                _ => current_token.push(chr),
+            }
+        }
+        self.clear_accum(&mut current_token, &mut tokens);
+        tokens
+    }
+
+    fn clear_accum(&self, current_token: &mut String, tokens: &mut Vec<Token>) {
+        let prev_token = std::mem::replace(current_token, String::new());
+        if prev_token.is_empty() {
+            return
+        }
+
+        if let Some(token) = self.table.get(&prev_token) {
+            tokens.push(token.clone());
+            return
+        }
+
+        // Number or var?
+        match prev_token.parse::<f32>() {
+            Ok(v) => tokens.push(Token::ConstFloat32(v)),
+            Err(_) => tokens.push(Token::LoadVar(prev_token)),
+        }
     }
 }
 
@@ -268,22 +307,15 @@ fn convert<I: Iterator<Item = Token>>(iter: &mut I) -> Result<Op> {
     Ok(op)
 }
 
-fn compile_line(stmt: &str) -> Result<Op> {
-    let stmt = remove_whitespace(stmt);
-    let tokens = tokenize(&stmt);
-    //println!("{tokens:#?}");
-    let tokens = to_rpn(tokens)?;
-    //println!("{tokens:#?}");
-    Ok(convert(&mut tokens.into_iter())?)
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
 
     #[test]
     fn single_line() {
-        let code = compile("h/2 - 200").unwrap();
+        let compiler = Compiler::new();
+
+        let code = compiler.compile("h/2 - 200").unwrap();
         #[rustfmt::skip]
         let code2 = vec![Op::Sub((
             Box::new(Op::Div((
@@ -294,7 +326,7 @@ mod tests {
         ))];
         assert_eq!(code, code2);
 
-        let code = compile("(x + h/2 + (y + 7)/5) - 200").unwrap();
+        let code = compiler.compile("(x + h/2 + (y + 7)/5) - 200").unwrap();
         #[rustfmt::skip]
         let code2 = vec![Op::Sub((
             Box::new(Op::Add((
@@ -319,4 +351,14 @@ mod tests {
         ))];
         assert_eq!(code, code2);
     }
+
+    #[test]
+    fn dosub() {
+        let mut compiler = Compiler::new();
+        compiler.add_const_f32("HELLO", 110.);
+
+        let code = compiler.compile("HELLO").unwrap();
+        let code2 = vec![Op::ConstFloat32(110.)];
+        assert_eq!(code, code2);
+    }
 }

+ 1 - 1
bin/darkwallet/src/expr/mod.rs

@@ -26,7 +26,7 @@ use darkfi_serial::{
 use std::io::{Read, Write};
 
 mod compile;
-pub use compile::compile;
+pub use compile::Compiler;
 
 #[derive(Clone, Debug, PartialEq, SerialEncodable, SerialDecodable)]
 pub enum SExprVal {