diff --git a/TODO.md b/TODO.md
index 076d365..f178de0 100644
--- a/TODO.md
+++ b/TODO.md
@@ -60,7 +60,6 @@
- Show base units on error
## Units
- - Abbreviations: kWh, bps, fps, dot/in, px/in, parts-per-x(ppm, ppb, ppt, ppq), percent(pct)
- Selective prefixes: tonne (k M G), Byte (TiB, etc), calorie (kcal)
- Print units with powers instead of /
- HMS for degrees
diff --git a/buildscript/constants.rs b/buildscript/constants.rs
new file mode 100644
index 0000000..add75c0
--- /dev/null
+++ b/buildscript/constants.rs
@@ -0,0 +1,110 @@
+use std::io::Write;
+use std::fs::OpenOptions;
+use std::path::Path;
+use toml::Table;
+
+
+
+pub fn write(target: &Path) {
+ let constants = include_str!("constants.toml").parse::
().unwrap();
+ let toml::Value::Array(constants) = &constants["constant"] else {panic!()};
+
+ let mut file = OpenOptions::new()
+ .write(true)
+ .create(true)
+ .truncate(true)
+ .open(target)
+ .unwrap();
+
+
+ writeln!(file,
+ concat!(
+ "#[derive(Debug)]\n",
+ "#[derive(Copy, Clone)]\n",
+ "pub enum Constant {{"
+ )
+ ).unwrap();
+
+ for c in constants {
+ writeln!(file,
+ "\t{},",
+ c["enum_name"].as_str().unwrap()
+ ).unwrap();
+ }
+
+ writeln!(file, "}}\n").unwrap();
+
+ // ToString
+ writeln!(file,
+ concat!(
+ "impl ToString for Constant {{\n",
+ "\tfn to_string(&self) -> String {{\n",
+ "\t\tString::from(match self {{"
+ )
+ ).unwrap();
+
+ for c in constants {
+ if c["strings"].is_array() {
+ writeln!(file,
+ "\t\t\tConstant::{e} => \"{s}\",",
+ e = c["enum_name"].as_str().unwrap(),
+ s = c["strings"].as_array().unwrap()[0].as_str().unwrap()
+ ).unwrap();
+ } else {
+ writeln!(file,
+ "\t\t\tConstant::{e} => \"{s}\",",
+ e = c["enum_name"].as_str().unwrap(),
+ s = c["strings"].as_str().unwrap()
+ ).unwrap();
+ }
+ }
+
+ writeln!(file, "\t\t}})\n\t}}\n}}\n").unwrap();
+
+
+ writeln!(file,
+ concat!(
+ "impl Constant {{\n",
+ "\tpub fn from_string(s: &str) -> Option {{\n",
+ "\t\tmatch s {{"
+ )
+ ).unwrap();
+
+ for c in constants {
+ if c["strings"].is_array() {
+ for s in c["strings"].as_array().unwrap() {
+ writeln!(file,
+ "\t\t\t\"{s}\" => Some(Constant::{e}),",
+ e = c["enum_name"].as_str().unwrap(),
+ s = s.as_str().unwrap()
+ ).unwrap();
+ }
+ } else {
+ writeln!(file,
+ "\t\t\t\"{s}\" => Some(Constant::{e}),",
+ e = c["enum_name"].as_str().unwrap(),
+ s = c["strings"].as_str().unwrap()
+ ).unwrap();
+ }
+ }
+
+ writeln!(file, "\t\t\t_ => None\n\t\t}}\n\t}}\n").unwrap();
+
+
+ writeln!(file,
+ concat!(
+ "\tpub fn value(&self) -> Token {{\n",
+ "\t\tmatch self {{"
+ )
+ ).unwrap();
+
+ for c in constants {
+ writeln!(file,
+ "\t\t\tConstant::{e} => parse(&String::from(\"{s}\")).unwrap(),",
+ e = c["enum_name"].as_str().unwrap(),
+ s = c["value"].as_str().unwrap()
+ ).unwrap();
+ }
+
+ writeln!(file, "\t\t}}\n\t}}\n}}").unwrap();
+}
\ No newline at end of file
diff --git a/buildscript/constants.toml b/buildscript/constants.toml
new file mode 100644
index 0000000..3bfa992
--- /dev/null
+++ b/buildscript/constants.toml
@@ -0,0 +1,76 @@
+
+[[constant]]
+enum_name = "Pi"
+strings = ["π", "pi"]
+value = "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067"
+
+[[constant]]
+enum_name = "Phi"
+strings = ["φ", "phi"]
+value = "1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137"
+
+[[constant]]
+enum_name = "Euler"
+strings = "e"
+value = "2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427"
+
+[[constant]]
+enum_name = "MPG"
+strings = "mpg"
+value = "mile/gallon"
+unit = true
+
+
+[[constant]]
+enum_name = "MPH"
+strings = "mph"
+value = "mile/hour"
+unit = true
+
+[[constant]]
+enum_name = "DPI"
+strings = "dpi"
+value = "dot/inch"
+unit = true
+
+[[constant]]
+enum_name = "PPI"
+strings = "ppi"
+value = "pixel/inch"
+unit = true
+
+[[constant]]
+enum_name = "FPS"
+strings = "fps"
+value = "frame/second"
+unit = true
+
+[[constant]]
+enum_name = "PCT"
+strings = "pct"
+value = "0.01"
+unit = true
+
+[[constant]]
+enum_name = "PPM"
+strings = "ppm"
+value = "1e-6"
+unit = true
+
+[[constant]]
+enum_name = "PPB"
+strings = "ppb"
+value = "1e-9"
+unit = true
+
+[[constant]]
+enum_name = "PPT"
+strings = "ppt"
+value = "1e-12"
+unit = true
+
+[[constant]]
+enum_name = "PPQ"
+strings = "ppq"
+value = "1e-15"
+unit = true
\ No newline at end of file
diff --git a/buildscript/main.rs b/buildscript/main.rs
index 579cb84..6c9e40f 100644
--- a/buildscript/main.rs
+++ b/buildscript/main.rs
@@ -1,278 +1,21 @@
use std::env;
-use std::io::Write;
-use std::fs::OpenOptions;
-use std::fs::File;
use std::path::Path;
-use toml::Table;
-use toml::Value;
-
-
-
-
-/// Create WholeUnit enum with
-/// basic impls. Should only be run once.
-fn write_wholeunit_main(mut file: &File, units: &Vec) {
- writeln!(file,
- concat!(
- "#[derive(Hash)]\n",
- "#[derive(Debug)]\n",
- "#[derive(Copy, Clone)]\n",
- "#[derive(Eq, PartialEq)]\n",
- "pub enum WholeUnit {{"
- )
- ).unwrap();
-
- for u in units {
- writeln!(file,
- "\t{},",
- u["enum_name"].as_str().unwrap()
- ).unwrap();
- }
-
- writeln!(file, "}}\n").unwrap();
-
- // ToString
- writeln!(file,
- concat!(
- "impl ToString for WholeUnit {{\n",
- "\tfn to_string(&self) -> String {{\n",
- "\t\tString::from(match self {{"
- )
- ).unwrap();
-
- for u in units {
- writeln!(file,
- "\t\t\tWholeUnit::{e} => \"{s}\",",
- s = u["print"].as_str().unwrap(),
- e = u["enum_name"].as_str().unwrap()
- ).unwrap();
- }
-
- writeln!(file, "\t\t}})\n\t}}\n}}\n").unwrap();
-
-
- // Properties
- writeln!(file,
- concat!(
- "impl WholeUnit {{\n",
- "\tfn no_space(&self) -> bool {{\n",
- "\t\tmatch self {{"
- )
- ).unwrap();
-
- for u in units {
- if u.as_table().unwrap().contains_key("no_space") {
- if u.as_table().unwrap()["no_space"].as_bool().unwrap() {
- writeln!(file,
- "\t\t\tWholeUnit::{} => true,",
- u["enum_name"].as_str().unwrap()
- ).unwrap();
- }
- }
- }
-
- writeln!(file, "\t\t\t_ => false\n\t\t}}\n\t}}\n}}").unwrap();
-}
-
-
-/// Create WholeUnit::base_factor().
-/// Should only be run once.
-fn write_wholeunit_base_factor(mut file: &File, units: &Vec) {
- writeln!(file,
- concat!(
- "impl WholeUnit {{\n",
- "\tfn base_factor(&self) -> Option {{\n",
- "\t\tmatch self {{"
- )
- ).unwrap();
-
- for u in units {
-
-
- if { // Base units should return None
- u.as_table().unwrap().contains_key("base") &&
- u["base"].as_bool().unwrap()
- } {
- writeln!(file,
- "\t\t\tWholeUnit::{} => None,",
- u["enum_name"].as_str().unwrap()
- ).unwrap();
- continue
- }
-
-
- writeln!(file,
- "\t\t\tWholeUnit::{} => Some(Quantity{{",
- u["enum_name"].as_str().unwrap()
- ).unwrap();
-
- match u["base_value_type"].as_str().unwrap() {
- "exact" => {
- writeln!(file,
- "\t\t\t\tscalar: Scalar::new_rational_from_string(\"{}\").unwrap(),",
- u["base_value"].as_str().unwrap(),
- ).unwrap();
- },
-
- "fract" => {
- writeln!(file,
- "\t\t\t\tscalar: Scalar::new_rational_from_frac({}, {}).unwrap(),",
- u["base_value"].as_array().unwrap()[0].as_integer().unwrap(),
- u["base_value"].as_array().unwrap()[1].as_integer().unwrap(),
- ).unwrap();
- },
-
- "approx" => {
- writeln!(file,
- "\t\t\t\tscalar: Scalar::new_float_from_string(\"{}\").unwrap(),",
- u["base_value"].as_str().unwrap(),
- ).unwrap();
- },
-
- _ => panic!()
- };
-
- writeln!(file,
- concat!(
- "\t\t\t\tunit: Unit::from_array(&[\n",
- "\t\t\t\t\t(FreeUnit{{whole: WholeUnit::{}, prefix: Prefix::None}}, Scalar::new_rational(-1f64).unwrap()),",
- ),
- u["enum_name"].as_str().unwrap()
- ).unwrap();
-
- for b in u["base_units"].as_array().unwrap() {
- writeln!(file,
- "\t\t\t\t\t(FreeUnit{{whole: WholeUnit::{u}, prefix: Prefix::None}}, Scalar::new_rational({p}f64).unwrap()),",
- u = b.as_table().unwrap()["u"].as_str().unwrap(),
- p = b.as_table().unwrap()["p"].as_integer().unwrap(),
- ).unwrap();
- }
-
- writeln!(file,
- concat!(
- "\t\t\t\t])\n",
- "\t\t\t}}),"
- ),
- ).unwrap();
- }
-
- writeln!(file, "\t\t}}\n\t}}\n}}").unwrap();
-}
-
-
-/// Write all SI prefixes.
-/// Used inside freeunit_from_string().
-fn prefix_si(mut file: &File, enum_name: &str, s: &str) {
- writeln!(file,
- concat!(
- "\t\t", "\"{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::None}}),\n",
- "\t\t", "\"Q{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Quetta}}),\n",
- "\t\t", "\"R{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Ronna}}),\n",
- "\t\t", "\"Y{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Yotta}}),\n",
- "\t\t", "\"Z{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Zetta}}),\n",
- "\t\t", "\"E{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Exa}}),\n",
- "\t\t", "\"P{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Peta}}),\n",
- "\t\t", "\"T{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Tera}}),\n",
- "\t\t", "\"G{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Giga}}),\n",
- "\t\t", "\"M{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Mega}}),\n",
- "\t\t", "\"k{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Kilo}}),\n",
- "\t\t", "\"h{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Hecto}}),\n",
- "\t\t", "\"da{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Deka}}),\n",
- "\t\t", "\"d{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Deci}}),\n",
- "\t\t", "\"c{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Centi}}),\n",
- "\t\t", "\"m{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Milli}}),\n",
- "\t\t", "\"u{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Micro}}),\n",
- "\t\t", "\"n{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Nano}}),\n",
- "\t\t", "\"p{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Pico}}),\n",
- "\t\t", "\"f{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Femto}}),\n",
- "\t\t", "\"a{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Atto}}),\n",
- "\t\t", "\"z{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Zepto}}),\n",
- "\t\t", "\"y{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Yocto}}),\n",
- "\t\t", "\"r{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Ronto}}),\n",
- "\t\t", "\"q{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Quecto}}),",
- ),
- e = enum_name,
- s = s
- ).unwrap();
-}
-
-
-/// Create freeunit_from_string().
-/// Should only be run once.
-fn write_freeunit_from_string(mut file: &File, units: &Vec) {
- writeln!(file,
- concat!(
- "#[inline(always)]\n",
- "fn freeunit_from_string(s: &str) -> Option {{\n",
- "\tmatch s {{"
- ),
- ).unwrap();
-
- for u in units {
- if u.as_table().unwrap().contains_key("parse") {
- for s in u["parse"].as_array().unwrap() {
- writeln!(file,
- "\t\t\"{}\" => Some(FreeUnit{{whole: WholeUnit::{}, prefix: Prefix::None}}),",
- s.as_str().unwrap(),
- u["enum_name"].as_str().unwrap()
- ).unwrap();
- }
- }
-
-
- if u.as_table().unwrap().contains_key("parse_with_prefix") {
- if u.as_table().unwrap()["parse_with_prefix"].is_array() {
- for p in u["parse_with_prefix"].as_array().unwrap() {
- prefix_si(
- &file,
- u["enum_name"].as_str().unwrap(),
- p.as_str().unwrap()
- );
- }
- } else {
- prefix_si(
- &file,
- u["enum_name"].as_str().unwrap(),
- u["parse_with_prefix"].as_str().unwrap()
- );
- }
- }
-
- writeln!(file, "").unwrap();
- }
-
- writeln!(file, "\t\t_ => None\n\t}}\n}}").unwrap();
-}
-
+mod units;
+mod constants;
fn main() -> Result<(), ()>{
let out_dir = env::var_os("OUT_DIR").unwrap();
- let dest_path = Path::new(&out_dir).join("units.rs");
println!("cargo:rerun-if-changed=buildscript/build.rs");
+ println!("cargo:rerun-if-changed=buildscript/constants.rs");
+ println!("cargo:rerun-if-changed=buildscript/units.rs");
println!("cargo:rerun-if-changed=buildscript/units.toml");
+ println!("cargo:rerun-if-changed=buildscript/constants.toml");
- let units = include_str!("units.toml").parse::().unwrap();
- let toml::Value::Array(units) = &units["unit"] else {panic!()};
-
- let mut file = OpenOptions::new()
- .write(true)
- .create(true)
- .truncate(true)
- .open(dest_path)
- .unwrap();
-
-
-
- write_wholeunit_main(&file, units);
- writeln!(file, "\n\n").unwrap();
-
- write_wholeunit_base_factor(&file, units);
- writeln!(file, "\n\n").unwrap();
-
- write_freeunit_from_string(&file, units);
+ units::write(&Path::new(&out_dir).join("units.rs"));
+ constants::write(&Path::new(&out_dir).join("constants.rs"));
return Ok(());
}
\ No newline at end of file
diff --git a/buildscript/units.rs b/buildscript/units.rs
new file mode 100644
index 0000000..3c73721
--- /dev/null
+++ b/buildscript/units.rs
@@ -0,0 +1,264 @@
+use std::path::Path;
+use std::fs::File;
+use std::fs::OpenOptions;
+use std::io::Write;
+use toml::Table;
+use toml::Value;
+
+
+
+/// Create WholeUnit enum with
+/// basic impls. Should only be run once.
+fn write_wholeunit_main(mut file: &File, units: &Vec) {
+ writeln!(file,
+ concat!(
+ "#[derive(Hash)]\n",
+ "#[derive(Debug)]\n",
+ "#[derive(Copy, Clone)]\n",
+ "#[derive(Eq, PartialEq)]\n",
+ "pub enum WholeUnit {{"
+ )
+ ).unwrap();
+
+ for u in units {
+ writeln!(file,
+ "\t{},",
+ u["enum_name"].as_str().unwrap()
+ ).unwrap();
+ }
+
+ writeln!(file, "}}\n").unwrap();
+
+ // ToString
+ writeln!(file,
+ concat!(
+ "impl ToString for WholeUnit {{\n",
+ "\tfn to_string(&self) -> String {{\n",
+ "\t\tString::from(match self {{"
+ )
+ ).unwrap();
+
+ for u in units {
+ writeln!(file,
+ "\t\t\tWholeUnit::{e} => \"{s}\",",
+ s = u["print"].as_str().unwrap(),
+ e = u["enum_name"].as_str().unwrap()
+ ).unwrap();
+ }
+
+ writeln!(file, "\t\t}})\n\t}}\n}}\n").unwrap();
+
+
+ // Properties
+ writeln!(file,
+ concat!(
+ "impl WholeUnit {{\n",
+ "\tfn no_space(&self) -> bool {{\n",
+ "\t\tmatch self {{"
+ )
+ ).unwrap();
+
+ for u in units {
+ if u.as_table().unwrap().contains_key("no_space") {
+ if u.as_table().unwrap()["no_space"].as_bool().unwrap() {
+ writeln!(file,
+ "\t\t\tWholeUnit::{} => true,",
+ u["enum_name"].as_str().unwrap()
+ ).unwrap();
+ }
+ }
+ }
+
+ writeln!(file, "\t\t\t_ => false\n\t\t}}\n\t}}\n}}").unwrap();
+}
+
+
+/// Create WholeUnit::base_factor().
+/// Should only be run once.
+fn write_wholeunit_base_factor(mut file: &File, units: &Vec) {
+ writeln!(file,
+ concat!(
+ "impl WholeUnit {{\n",
+ "\tfn base_factor(&self) -> Option {{\n",
+ "\t\tmatch self {{"
+ )
+ ).unwrap();
+
+ for u in units {
+
+
+ if { // Base units should return None
+ u.as_table().unwrap().contains_key("base") &&
+ u["base"].as_bool().unwrap()
+ } {
+ writeln!(file,
+ "\t\t\tWholeUnit::{} => None,",
+ u["enum_name"].as_str().unwrap()
+ ).unwrap();
+ continue
+ }
+
+
+ writeln!(file,
+ "\t\t\tWholeUnit::{} => Some(Quantity{{",
+ u["enum_name"].as_str().unwrap()
+ ).unwrap();
+
+ match u["base_value_type"].as_str().unwrap() {
+ "exact" => {
+ writeln!(file,
+ "\t\t\t\tscalar: Scalar::new_rational_from_string(\"{}\").unwrap(),",
+ u["base_value"].as_str().unwrap(),
+ ).unwrap();
+ },
+
+ "fract" => {
+ writeln!(file,
+ "\t\t\t\tscalar: Scalar::new_rational_from_frac({}, {}).unwrap(),",
+ u["base_value"].as_array().unwrap()[0].as_integer().unwrap(),
+ u["base_value"].as_array().unwrap()[1].as_integer().unwrap(),
+ ).unwrap();
+ },
+
+ "approx" => {
+ writeln!(file,
+ "\t\t\t\tscalar: Scalar::new_float_from_string(\"{}\").unwrap(),",
+ u["base_value"].as_str().unwrap(),
+ ).unwrap();
+ },
+
+ _ => panic!()
+ };
+
+ writeln!(file,
+ concat!(
+ "\t\t\t\tunit: Unit::from_array(&[\n",
+ "\t\t\t\t\t(FreeUnit{{whole: WholeUnit::{}, prefix: Prefix::None}}, Scalar::new_rational(-1f64).unwrap()),",
+ ),
+ u["enum_name"].as_str().unwrap()
+ ).unwrap();
+
+ for b in u["base_units"].as_array().unwrap() {
+ writeln!(file,
+ "\t\t\t\t\t(FreeUnit{{whole: WholeUnit::{u}, prefix: Prefix::None}}, Scalar::new_rational({p}f64).unwrap()),",
+ u = b.as_table().unwrap()["u"].as_str().unwrap(),
+ p = b.as_table().unwrap()["p"].as_integer().unwrap(),
+ ).unwrap();
+ }
+
+ writeln!(file,
+ concat!(
+ "\t\t\t\t])\n",
+ "\t\t\t}}),"
+ ),
+ ).unwrap();
+ }
+
+ writeln!(file, "\t\t}}\n\t}}\n}}").unwrap();
+}
+
+
+/// Write all SI prefixes.
+/// Used inside freeunit_from_string().
+fn prefix_si(mut file: &File, enum_name: &str, s: &str) {
+ writeln!(file,
+ concat!(
+ "\t\t", "\"{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::None}}),\n",
+ "\t\t", "\"Q{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Quetta}}),\n",
+ "\t\t", "\"R{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Ronna}}),\n",
+ "\t\t", "\"Y{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Yotta}}),\n",
+ "\t\t", "\"Z{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Zetta}}),\n",
+ "\t\t", "\"E{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Exa}}),\n",
+ "\t\t", "\"P{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Peta}}),\n",
+ "\t\t", "\"T{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Tera}}),\n",
+ "\t\t", "\"G{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Giga}}),\n",
+ "\t\t", "\"M{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Mega}}),\n",
+ "\t\t", "\"k{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Kilo}}),\n",
+ "\t\t", "\"h{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Hecto}}),\n",
+ "\t\t", "\"da{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Deka}}),\n",
+ "\t\t", "\"d{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Deci}}),\n",
+ "\t\t", "\"c{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Centi}}),\n",
+ "\t\t", "\"m{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Milli}}),\n",
+ "\t\t", "\"u{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Micro}}),\n",
+ "\t\t", "\"n{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Nano}}),\n",
+ "\t\t", "\"p{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Pico}}),\n",
+ "\t\t", "\"f{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Femto}}),\n",
+ "\t\t", "\"a{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Atto}}),\n",
+ "\t\t", "\"z{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Zepto}}),\n",
+ "\t\t", "\"y{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Yocto}}),\n",
+ "\t\t", "\"r{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Ronto}}),\n",
+ "\t\t", "\"q{s}\" => Some(FreeUnit{{whole: WholeUnit::{e}, prefix: Prefix::Quecto}}),",
+ ),
+ e = enum_name,
+ s = s
+ ).unwrap();
+}
+
+
+/// Create freeunit_from_string().
+/// Should only be run once.
+fn write_freeunit_from_string(mut file: &File, units: &Vec) {
+ writeln!(file,
+ concat!(
+ "#[inline(always)]\n",
+ "fn freeunit_from_string(s: &str) -> Option {{\n",
+ "\tmatch s {{"
+ ),
+ ).unwrap();
+
+ for u in units {
+ if u.as_table().unwrap().contains_key("parse") {
+ for s in u["parse"].as_array().unwrap() {
+ writeln!(file,
+ "\t\t\"{}\" => Some(FreeUnit{{whole: WholeUnit::{}, prefix: Prefix::None}}),",
+ s.as_str().unwrap(),
+ u["enum_name"].as_str().unwrap()
+ ).unwrap();
+ }
+ }
+
+
+ if u.as_table().unwrap().contains_key("parse_with_prefix") {
+ if u.as_table().unwrap()["parse_with_prefix"].is_array() {
+ for p in u["parse_with_prefix"].as_array().unwrap() {
+ prefix_si(
+ &file,
+ u["enum_name"].as_str().unwrap(),
+ p.as_str().unwrap()
+ );
+ }
+ } else {
+ prefix_si(
+ &file,
+ u["enum_name"].as_str().unwrap(),
+ u["parse_with_prefix"].as_str().unwrap()
+ );
+ }
+ }
+
+ writeln!(file, "").unwrap();
+ }
+
+ writeln!(file, "\t\t_ => None\n\t}}\n}}").unwrap();
+}
+
+pub fn write(target: &Path) {
+ let units = include_str!("units.toml").parse::().unwrap();
+ let toml::Value::Array(units) = &units["unit"] else {panic!()};
+
+ let mut file = OpenOptions::new()
+ .write(true)
+ .create(true)
+ .truncate(true)
+ .open(target)
+ .unwrap();
+
+
+ write_wholeunit_main(&file, units);
+ writeln!(file, "\n\n").unwrap();
+
+ write_wholeunit_base_factor(&file, units);
+ writeln!(file, "\n\n").unwrap();
+
+ write_freeunit_from_string(&file, units);
+}
diff --git a/src/evaluate/constant.rs b/src/evaluate/constant.rs
deleted file mode 100644
index 539eefc..0000000
--- a/src/evaluate/constant.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-use crate::parser::Token;
-use crate::parser::Constant;
-use crate::quantity::Quantity;
-use crate::quantity::Unit;
-
-use super::EvalError;
-
-pub fn eval_constant(c: &Constant) -> Result {
- Ok(match c {
- // Mathematical constants
- // 100 digits of each.
- Constant::Pi => { Token::Quantity(Quantity::new_float_from_string(
- "3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067"
- ).unwrap())},
-
- Constant::E => { Token::Quantity(Quantity::new_float_from_string(
- "2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427"
- ).unwrap()) },
-
- Constant::Phi => { Token::Quantity(Quantity::new_float_from_string(
- "1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137"
- ).unwrap()) },
-
- Constant::MPG => {
- let mut q = Quantity::new_float_from_string("1").unwrap();
- q.set_unit(
- (
- Unit::from_string("mile").unwrap() /
- Unit::from_string("gallon").unwrap()
- ).unit
- );
- Token::Quantity(q)
- },
-
- Constant::MPH => {
- let mut q = Quantity::new_float_from_string("1").unwrap();
- q.set_unit(
- (
- Unit::from_string("mile").unwrap() /
- Unit::from_string("hour").unwrap()
- ).unit
- );
- Token::Quantity(q)
- },
- })
-}
\ No newline at end of file
diff --git a/src/evaluate/evaluate.rs b/src/evaluate/evaluate.rs
index bc0503b..ccc117d 100644
--- a/src/evaluate/evaluate.rs
+++ b/src/evaluate/evaluate.rs
@@ -2,7 +2,6 @@ use crate::parser::Token;
use crate::parser::Operator;
use super::operator::eval_operator;
-use super::constant::eval_constant;
use super::function::eval_function;
use super::EvalError;
@@ -13,8 +12,8 @@ pub fn evaluate(t: &Token) -> Result {
coords.push(0);
'outer: loop {
-
let mut h = &mut g;
+
for t in coords.iter() {
let inner = h.get_args_mut();
@@ -32,7 +31,7 @@ pub fn evaluate(t: &Token) -> Result {
loop {
e = match e {
Token::Quantity(_) => { break; },
- Token::Constant(c) => { eval_constant(&c)? }
+ Token::Constant(c) => { evaluate(&c.value()).unwrap() }
Token::Operator(Operator::Function(f), v) => { eval_function(&f, &v)? }
Token::Operator(o, v) => { eval_operator(&o, &v)? }
};
@@ -50,22 +49,13 @@ pub fn evaluate(t: &Token) -> Result {
}
-
match h {
- Token::Operator(_,_) => {
- coords.push(0);
- continue 'outer;
- },
-
- Token::Constant(_) => {
- coords.push(0);
- continue 'outer;
- },
+ Token::Operator(_,_) => { coords.push(0); },
+ Token::Constant(_) => { coords.push(0); },
Token::Quantity(_) => {
let l = coords.pop().unwrap();
coords.push(l + 1);
- continue 'outer;
}
};
}
diff --git a/src/parser/pretoken.rs b/src/parser/pretoken.rs
index 6247db4..26d9453 100644
--- a/src/parser/pretoken.rs
+++ b/src/parser/pretoken.rs
@@ -74,14 +74,7 @@ impl PreToken {
},
PreToken::PreWord(l, s) => {
- let c = match &s[..] {
- "π"|"pi" => { Some(Constant::Pi)},
- "e" => { Some(Constant::E) },
- "phi"|"φ" => { Some(Constant::Phi) },
- "mpg" => { Some(Constant::MPG) },
- "mph" => { Some(Constant::MPH) },
- _ => { None }
- };
+ let c = Constant::from_string(&s);
if c.is_some() {
return Ok(Token::Constant(c.unwrap()));
diff --git a/src/parser/token/constant.rs b/src/parser/token/constant.rs
deleted file mode 100644
index f303cd4..0000000
--- a/src/parser/token/constant.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-#[derive(Debug)]
-#[derive(Clone)]
-pub enum Constant {
- // Fake units
- MPG,
- MPH,
-
- // Mathematics
- Pi,
- Phi,
- E,
-}
-
-impl Constant {
- pub fn to_string(&self) -> String {
- match self {
- // Fake units
- Constant::MPG => { String::from("mpg") },
- Constant::MPH => { String::from("mph") },
-
- // Mathematics
- Constant::Pi => { String::from("π") },
- Constant::Phi => { String::from("φ") },
- Constant::E => { String::from("e") }
- }
- }
-}
\ No newline at end of file
diff --git a/src/parser/token/mod.rs b/src/parser/token/mod.rs
index 564b412..0aec541 100644
--- a/src/parser/token/mod.rs
+++ b/src/parser/token/mod.rs
@@ -1,9 +1,11 @@
mod operator;
mod function;
mod token;
-mod constant;
pub use self::operator::Operator;
pub use self::function::Function;
pub use self::token::Token;
-pub use self::constant::Constant;
\ No newline at end of file
+
+
+use super::parse;
+include!(concat!(env!("OUT_DIR"), "/constants.rs"));
\ No newline at end of file