///|
pub(all) enum CommandResult {
Ok(String)
Err(String)
} derive(Eq, Debug)
///|
pub impl Show for CommandResult with fn output(self, logger) {
match self {
Ok(value) => {
logger.write_string("Ok(\"")
logger.write_string(value)
logger.write_string("\")")
}
Err(message) => {
logger.write_string("Err(\"")
logger.write_string(message)
logger.write_string("\")")
}
}
}
///|
pub struct InputBinding {
name : String
value : String
} derive(Eq, Debug)
///|
pub fn InputBinding::new(name : String, value : String) -> InputBinding {
{ name, value }
}
///|
pub fn InputBinding::name(self : InputBinding) -> String {
self.name
}
///|
pub fn InputBinding::value(self : InputBinding) -> String {
self.value
}
///|
priv enum EnvBuildResult {
BuiltEnv(@formula_common.FormulaEnv)
EnvError(String)
}
///|
pub fn parse_format_style(style : String) -> @unit.FormatStyle? {
match style {
"ascii" => Some(Ascii)
"si" => Some(Si)
"latex" => Some(Latex)
_ => None
}
}
///|
pub fn run_list() -> CommandResult {
let entries = @formula_catalog.all().entries()
let mut output = ""
for entry in entries {
output = output + "\{entry.name()}\t\{entry.domain()}\t\{entry.display()}\n"
}
Ok(output)
}
///|
fn format_inputs(inputs : Array[@formula_common.FormulaInput]) -> String {
let mut output = ""
for input in inputs {
output = output +
" --\{input.name()} dimension: \{input.dimension()}\n"
}
output
}
///|
pub fn run_show(name : String) -> CommandResult {
match @formula_catalog.all().lookup(name) {
None => Err("unknown formula `\{name}`")
Some(entry) =>
Ok(
"name: \{entry.name()}\n" +
"domain: \{entry.domain()}\n" +
"formula: \{entry.display()}\n" +
"description: \{entry.description()}\n" +
"output dimension: \{entry.output_dimension()}\n" +
"inputs:\n" +
format_inputs(entry.inputs()),
)
}
}
///|
fn lookup_binding(bindings : Array[InputBinding], name : String) -> String? {
for binding in bindings {
if binding.name() == name {
return Some(binding.value())
}
}
None
}
///|
fn build_env(
inputs : Array[@formula_common.FormulaInput],
bindings : Array[InputBinding],
) -> EnvBuildResult {
let mut env = @formula_common.FormulaEnv::new()
let unit_catalog = @preset.all()
.with_unit("ohm", @electromagnetism.ohm)
.with_unit("Ohm", @electromagnetism.ohm)
for input in inputs {
match lookup_binding(bindings, input.name()) {
None => return EnvError("missing input `\{input.name()}`")
Some(text) => {
let value = @parser.parse_quantity(unit_catalog, text) catch {
err =>
return EnvError("invalid quantity for `\{input.name()}`: \{err}")
}
if !value.dimension().is_same(input.dimension()) {
return EnvError(
"input `\{input.name()}` expects dimension \{input.dimension()}, got \{value.dimension()}",
)
}
env = env.with_input(input.name(), value)
}
}
}
BuiltEnv(env)
}
///|
pub fn run_calc(
name : String,
bindings : Array[InputBinding],
format? : String = "ascii",
) -> CommandResult {
let style = match parse_format_style(format) {
Some(style) => style
None =>
return Err(
"unknown output format `\{format}`; expected ascii, si, or latex",
)
}
let entry = match @formula_catalog.all().lookup(name) {
Some(entry) => entry
None => return Err("unknown formula `\{name}`")
}
let env = match build_env(entry.inputs(), bindings) {
BuiltEnv(env) => env
EnvError(message) => return Err(message)
}
let result = entry.eval(env) catch {
err => return Err("failed to evaluate `\{name}`: \{err}")
}
Ok(@quantity.format_quantity_with(result, style))
}