add documentation

This commit is contained in:
ゆめ 2023-08-22 22:23:11 -05:00
parent 6a6ebd315e
commit fbde3594cd
9 changed files with 48 additions and 0 deletions

View file

@ -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) {

View file

@ -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 {

View file

@ -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>,

View file

@ -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 {

View file

@ -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();

View file

@ -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();

View file

@ -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;

View file

@ -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();

View file

@ -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>);