From fbde3594cd4903daf72aee7e7b10102c550fcb82 Mon Sep 17 00:00:00 2001
From: eternal-flame-AD <yume@yumechi.jp>
Date: Tue, 22 Aug 2023 22:23:11 -0500
Subject: [PATCH] add documentation

---
 crates/unitdc-cli/src/main.rs    |  1 +
 crates/unitdc-web/src/lib.rs     |  2 ++
 src/interpreter/mod.rs           |  4 ++++
 src/interpreter/ops.rs           | 21 +++++++++++++++++++++
 src/interpreter/ops_macros.rs    |  9 +++++++++
 src/interpreter/ops_variables.rs |  2 ++
 src/lib.rs                       |  4 ++++
 src/quantity/mod.rs              |  3 +++
 src/quantity/units.rs            |  2 ++
 9 files changed, 48 insertions(+)

diff --git a/crates/unitdc-cli/src/main.rs b/crates/unitdc-cli/src/main.rs
index 5081116..2ad8ac5 100644
--- a/crates/unitdc-cli/src/main.rs
+++ b/crates/unitdc-cli/src/main.rs
@@ -17,6 +17,7 @@ fn main() {
         .run_str(include_str!("../../../unitdc.rc"))
         .expect("unitdc.rc should run");
 
+    // REPL loop
     for line in std::io::stdin().lines() {
         let line = line.expect("line should exist");
         if let Err(e) = interpreter.run_str(&line) {
diff --git a/crates/unitdc-web/src/lib.rs b/crates/unitdc-web/src/lib.rs
index 56ba757..5452001 100644
--- a/crates/unitdc-web/src/lib.rs
+++ b/crates/unitdc-web/src/lib.rs
@@ -13,6 +13,7 @@ extern "C" {
     fn log(s: String);
 }
 
+/// Runs a string in the interpreter.
 #[wasm_bindgen]
 pub fn unitdc_input(input: String) -> Result<(), JsValue> {
     unsafe {
@@ -23,6 +24,7 @@ pub fn unitdc_input(input: String) -> Result<(), JsValue> {
     Ok(())
 }
 
+/// Initializes the interpreter, taking a callback function to send output to.
 #[wasm_bindgen]
 pub fn unitdc_init(js_output: Function) {
     unsafe {
diff --git a/src/interpreter/mod.rs b/src/interpreter/mod.rs
index 5d7fc42..bcfc052 100644
--- a/src/interpreter/mod.rs
+++ b/src/interpreter/mod.rs
@@ -13,8 +13,11 @@ use crate::{
 
 use thiserror::Error;
 
+/// All other operations.
 pub mod ops;
+/// Macro operations.
 pub mod ops_macros;
+/// Variable I/O operations.
 pub mod ops_variables;
 
 pub struct Interpreter<'a> {
@@ -64,6 +67,7 @@ impl<'a> Interpreter<'a> {
             output,
         }
     }
+    /// Reads all tokens from the tokenizer and processes them.
     pub fn process_tokens<R: Read>(
         &mut self,
         tokenizer: &mut Tokenizer<R>,
diff --git a/src/interpreter/ops.rs b/src/interpreter/ops.rs
index 5f90476..75f66a0 100644
--- a/src/interpreter/ops.rs
+++ b/src/interpreter/ops.rs
@@ -12,10 +12,17 @@ use crate::{
 use super::{Interpreter, InterpreterError, InterpreterResult, Output};
 
 impl<'a> Interpreter<'a> {
+    /// A literal number input, pushes a unit-less quantity to the stack.
     pub fn op_number(&mut self, number: BigRational) -> InterpreterResult<()> {
         self.stack.push(Quantity::new(number, UnitCombo::new()));
         Ok(())
     }
+    /// A literal unit input.
+    ///
+    /// - If the unit is unit-less (1), the top of the stack will be converted to a unit-less quantity.
+    /// - If the top of the stack is a unit-less quantity, it will be converted to the given unit.
+    /// - If the top of the stack is a quantity with equivalent units, it will be converted to the given unit.
+    /// - Otherwise, an error will be returned.
     pub fn op_unit(&mut self, unit: &str) -> InterpreterResult<()> {
         let mut q = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
 
@@ -67,6 +74,7 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Adds the top two quantities on the stack.
     pub fn op_add(&mut self) -> InterpreterResult<()> {
         let rhs = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
         let lhs = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
@@ -76,6 +84,7 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Subtracts the top two quantities on the stack.
     pub fn op_sub(&mut self) -> InterpreterResult<()> {
         let rhs = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
         let lhs = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
@@ -85,6 +94,7 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Multiplies the top two quantities on the stack.
     pub fn op_mul(&mut self) -> InterpreterResult<()> {
         let rhs = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
         let lhs = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
@@ -93,6 +103,7 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Divides the top two quantities on the stack.
     pub fn op_div(&mut self) -> InterpreterResult<()> {
         let rhs = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
         let lhs = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
@@ -101,6 +112,7 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Prints the top of the stack without altering it.
     pub fn op_p(&mut self) -> InterpreterResult<()> {
         let q = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
 
@@ -110,6 +122,7 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Prints the top of the stack and pops it.
     pub fn op_n(&mut self) -> InterpreterResult<()> {
         let q = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
 
@@ -117,11 +130,13 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Prints the entire stack.
     pub fn op_f(&mut self) -> InterpreterResult<()> {
         (self.output)(Output::QuantityList(self.stack.clone()));
 
         Ok(())
     }
+    /// Duplicates the top of the stack.
     pub fn op_d(&mut self) -> InterpreterResult<()> {
         let q = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
 
@@ -130,11 +145,13 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Clears the stack.
     pub fn op_c(&mut self) -> InterpreterResult<()> {
         self.stack.clear();
 
         Ok(())
     }
+    /// Swaps the top two elements of the stack.
     pub fn op_r(&mut self) -> InterpreterResult<()> {
         let a = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
         let b = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
@@ -144,6 +161,7 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Prints a summary of the unit system, including all base units, derived units, and their scale and offset.
     pub fn op_upper_u(&mut self) -> InterpreterResult<()> {
         let mut output = String::from("Base units:\n");
 
@@ -165,9 +183,11 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Invokes the unit solver. See [here](https://github.com/eternal-flame-AD/unitdc-rs/wiki/The-Unit-Solver) for instructions.
     pub fn op_s(&mut self) -> InterpreterResult<()> {
         let target = self.stack.pop().ok_or(InterpreterError::StackUnderflow)?;
 
+        // first figure out how many known quantities we have
         let n_src_quantities = target.number_in_derived_unit().to_integer();
         if n_src_quantities.to_usize().unwrap_or(0) > self.stack.len() {
             return Err(InterpreterError::StackUnderflow);
@@ -176,6 +196,7 @@ impl<'a> Interpreter<'a> {
             .stack
             .split_off(self.stack.len() - n_src_quantities.to_usize().unwrap_or(0));
         let dst_unit = target.unit.reduce();
+        // Check that all units involved are present
         let mut units_involved = Vec::new();
         for q in &src_quantities {
             for u in &q.unit.0 {
diff --git a/src/interpreter/ops_macros.rs b/src/interpreter/ops_macros.rs
index 5e83b33..c0ad8a6 100644
--- a/src/interpreter/ops_macros.rs
+++ b/src/interpreter/ops_macros.rs
@@ -3,6 +3,10 @@ use crate::quantity::units::{BaseUnit, DerivedUnit};
 use super::{Interpreter, InterpreterError, InterpreterResult};
 
 impl<'a> Interpreter<'a> {
+    /// Defines a new base unit.
+    ///
+    /// For example to define a unit "usd" (US Dollar), you would do:
+    /// `@base(usd)`
     pub fn op_macro_baseunit(&mut self, arg: &str) -> InterpreterResult<()> {
         let symbol = arg.trim();
 
@@ -16,6 +20,11 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Defines a new derived unit.
+    ///
+    /// This is done by popping a "scale" and then an "offset" from the stack.
+    /// For example, to define a new unit "mpg" (miles per gallon), you would do:
+    /// `0 (mi) 1 (gal) / 1 (mi) 1 (gal) / @derived(mpg)`
     pub fn op_macro_derivedunit(&mut self, arg: &str) -> InterpreterResult<()> {
         let symbol = arg.trim();
 
diff --git a/src/interpreter/ops_variables.rs b/src/interpreter/ops_variables.rs
index ae041b0..f4c2fd0 100644
--- a/src/interpreter/ops_variables.rs
+++ b/src/interpreter/ops_variables.rs
@@ -1,6 +1,7 @@
 use super::{Interpreter, InterpreterError, InterpreterResult};
 
 impl<'a> Interpreter<'a> {
+    /// Pops a quantity from the stack and stores it in a variable.
     pub fn op_store(&mut self, arg: &str) -> InterpreterResult<()> {
         let symbol = arg.trim();
 
@@ -10,6 +11,7 @@ impl<'a> Interpreter<'a> {
 
         Ok(())
     }
+    /// Pushes a quantity from a variable onto the stack.
     pub fn op_recall(&mut self, arg: &str) -> InterpreterResult<()> {
         let symbol = arg.trim();
 
diff --git a/src/lib.rs b/src/lib.rs
index 0bc033b..823603a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,4 +1,8 @@
+/// Interpreter for UnitDC expressions.
 pub mod interpreter;
+/// A module for evaluating linear systems of equations.
 pub mod linear_system;
+/// A module for manipulating units and quantities.
 pub mod quantity;
+/// Tokenizer for the interpreter.
 pub mod tokenizer;
diff --git a/src/quantity/mod.rs b/src/quantity/mod.rs
index dcceb98..ff8f432 100644
--- a/src/quantity/mod.rs
+++ b/src/quantity/mod.rs
@@ -12,6 +12,7 @@ pub mod units;
 
 use units::{DerivedUnit, UnitCombo};
 
+/// A quantity of a combination of a number, the unit combination, and a list of derived units to use when formatting the quantity.
 #[derive(Debug, Clone, PartialEq, Deserialize)]
 pub struct Quantity {
     pub number: BigRational,
@@ -41,6 +42,7 @@ pub enum QuantityError {
 }
 
 impl Quantity {
+    /// Create a new quantity with the given number and unit combination.
     pub fn new(number: BigRational, unit: UnitCombo) -> Self {
         Quantity {
             number,
@@ -48,6 +50,7 @@ impl Quantity {
             use_derived_unit: Vec::new(),
         }
     }
+    /// Computes the "user-facing" number of the quantity, considering the offset and scale of matching derived units.
     pub fn number_in_derived_unit(&self) -> BigRational {
         let mut number = self.number.clone();
 
diff --git a/src/quantity/units.rs b/src/quantity/units.rs
index 695e86d..9f97aa4 100644
--- a/src/quantity/units.rs
+++ b/src/quantity/units.rs
@@ -124,12 +124,14 @@ impl Display for DerivedUnit {
     }
 }
 
+/// A `UnitExponent` is the combination of a base unit and an exponent.
 #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
 pub struct UnitExponent {
     pub unit: BaseUnit,
     pub exponent: i32,
 }
 
+/// A `UnitCombo` is a combination of `UnitExponent`s, which described an arbitrary "unit".
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct UnitCombo(pub Vec<UnitExponent>);