From 9a1247ec3d4946d33f3dd7b385414802a3048792 Mon Sep 17 00:00:00 2001
From: eternal-flame-AD <yume@yumechi.jp>
Date: Tue, 22 Aug 2023 21:43:31 -0500
Subject: [PATCH] U operator

---
 crates/unitdc-web/ui/src/App.tsx              |  2 +-
 .../unitdc-web/ui/src/components/Keyboard.tsx |  1 +
 src/interpreter/mod.rs                        |  1 +
 src/interpreter/ops.rs                        | 21 +++++++++++++++++++
 src/quantity/units.rs                         | 16 ++++++++++++++
 src/tokenizer/mod.rs                          |  1 +
 6 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/crates/unitdc-web/ui/src/App.tsx b/crates/unitdc-web/ui/src/App.tsx
index 70575b6..bfaa7f2 100644
--- a/crates/unitdc-web/ui/src/App.tsx
+++ b/crates/unitdc-web/ui/src/App.tsx
@@ -179,7 +179,7 @@ function App() {
                   )
                 case 'message':
                   return (
-                    <div key={index}>Message: {cell.text}</div>
+                    <pre key={index}>{cell.text}</pre>
                   )
               }
             })
diff --git a/crates/unitdc-web/ui/src/components/Keyboard.tsx b/crates/unitdc-web/ui/src/components/Keyboard.tsx
index 866ee47..2d6fcdd 100644
--- a/crates/unitdc-web/ui/src/components/Keyboard.tsx
+++ b/crates/unitdc-web/ui/src/components/Keyboard.tsx
@@ -127,6 +127,7 @@ export function Keyboard(props: KeyboardProps) {
             </div>
             <div className="keyboard-col">
                 <UiActionButton action="clear" text="CLR" />
+                <TokenButton token="U" tokentype="operator" />
                 {
                     ["m", "mol", "M", "Da"].map((token) => {
                         return (
diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs
index ed0d449..5d7fc42 100644
--- a/src/interpreter/mod.rs
+++ b/src/interpreter/mod.rs
@@ -86,6 +86,7 @@ impl<'a> Interpreter<'a> {
                 Token::Operator('d') => self.op_d()?,
                 Token::Operator('r') => self.op_r()?,
                 Token::Operator('s') => self.op_s()?,
+                Token::Operator('U') => self.op_upper_u()?,
                 Token::VarRecall(name) => self.op_recall(&name)?,
                 Token::VarStore(name) => self.op_store(&name)?,
                 Token::MacroInvoke((name, args)) => match name.as_str() {
diff --git a/src/interpreter/ops.rs b/src/interpreter/ops.rs
index 2981fc6..5f90476 100644
--- a/src/interpreter/ops.rs
+++ b/src/interpreter/ops.rs
@@ -144,6 +144,27 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    pub fn op_upper_u(&mut self) -> InterpreterResult<()> {
+        let mut output = String::from("Base units:\n");
+
+        for u in &self.unit_system.base_units() {
+            output.push_str(&format!("{}, ", u.symbol));
+        }
+        output.pop();
+        output.pop();
+        output.push_str("\n\nDerived units:\n");
+
+        for u in &self.unit_system.derived_units() {
+            output.push_str(&format!(
+                "{} = {} ({}) + {}\n",
+                u.symbol, u.scale, u.exponents, u.offset
+            ));
+        }
+
+        (self.output)(Output::Message(output));
+
+        Ok(())
+    }
     pub fn op_s(&mut self) -> InterpreterResult<()> {
         let target = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
 
diff --git a/src/quantity/units.rs b/src/quantity/units.rs
index 1950b29..695e86d 100644
--- a/src/quantity/units.rs
+++ b/src/quantity/units.rs
@@ -55,6 +55,22 @@ impl UnitSystem {
     pub fn push_derived_unit(&mut self, unit: DerivedUnit) {
         self.derived_units.insert(unit.symbol.clone(), unit);
     }
+    pub fn base_units(&self) -> Vec<BaseUnit> {
+        let mut base_units = Vec::new();
+        for unit in self.base_units.values() {
+            base_units.push(unit.clone());
+        }
+        base_units.sort_by(|a, b| a.symbol.cmp(&b.symbol));
+        base_units
+    }
+    pub fn derived_units(&self) -> Vec<DerivedUnit> {
+        let mut derived_units = Vec::new();
+        for unit in self.derived_units.values() {
+            derived_units.push(unit.clone());
+        }
+        derived_units.sort_by(|a, b| format!("{}", a.exponents).cmp(&format!("{}", b.exponents)));
+        derived_units
+    }
 }
 
 #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
diff --git a/src/tokenizer/mod.rs b/src/tokenizer/mod.rs
index 97a56da..da25a35 100644
--- a/src/tokenizer/mod.rs
+++ b/src/tokenizer/mod.rs
@@ -152,6 +152,7 @@ impl<R: std::io::Read> Tokenizer<R> {
             Some('d') => Ok(Some(Token::Operator('d'))),
             Some('r') => Ok(Some(Token::Operator('r'))),
             Some('s') => Ok(Some(Token::Operator('s'))),
+            Some('U') => Ok(Some(Token::Operator('U'))),
             Some('#') => {
                 while let Some(c) = self.next_char().map_err(TokenizerError::IOError)? {
                     match c {