329 lines
12 KiB
Nix
329 lines
12 KiB
Nix
{ core, ... }:
|
|
let
|
|
inherit(core) debug integer number list string type;
|
|
|
|
formatSign# string? -> string
|
|
= sign:
|
|
if sign != null
|
|
then
|
|
{
|
|
"+" = "+";
|
|
"-" = "-";
|
|
"+-" = "{\\pm}";
|
|
"-+" = "{\\mp}";
|
|
}.${sign} or "{${sign}}"
|
|
else
|
|
"";
|
|
|
|
Unit#: U: ToUnit @ U -> Unit | !
|
|
= unit:
|
|
type.matchPrimitiveOrPanic unit
|
|
{
|
|
null = { inherit unit; };
|
|
set
|
|
= {
|
|
prefix = unit.prefix or null;
|
|
inherit unit;
|
|
sign = unit.sign or null;
|
|
exp = unit.exp or null;
|
|
};
|
|
string = parseUnit unit;
|
|
};
|
|
|
|
parseUnit#: string -> Unit
|
|
= let
|
|
prefixes = "yotta|zetta|exa|peta|tera|giga|mega|kilo|hecto|deca";
|
|
prefixes' = "deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto";
|
|
regex = "(${prefixes}|${prefixes'})?([A-Za-z]+)([-+])?([0-9]+|[0-9]*[.][0-9]*)?";
|
|
in
|
|
unit:
|
|
let
|
|
parsed = string.match regex unit;
|
|
in
|
|
if unit == "cm-1"
|
|
then
|
|
{
|
|
prefix = null;
|
|
inherit unit;
|
|
sign = null;
|
|
exp = null;
|
|
}
|
|
else if unit == ""
|
|
then
|
|
null
|
|
else if parsed != null
|
|
then
|
|
{
|
|
prefix = list.get parsed 0;
|
|
unit = list.get parsed 1;
|
|
sign = list.get parsed 2;
|
|
exp = list.get parsed 3;
|
|
}
|
|
else
|
|
debug.panic "parseUnit" { data = unit; text = "Cannot parse unit:"; };
|
|
|
|
formatUnit#: U: ToUnit @ [ U ] | U -> string
|
|
= unit:
|
|
let
|
|
text = formatUnit' unit;
|
|
in
|
|
if text != null
|
|
then
|
|
"\\ensuremath{${text}}"
|
|
else
|
|
"";
|
|
|
|
formatUnit'#: U: ToUnit @ [ U ] | U -> string
|
|
= maybeUnit:
|
|
if list.isInstanceOf maybeUnit
|
|
then
|
|
string.concatMappedWith formatUnit' "\\cdot" maybeUnit
|
|
else
|
|
let
|
|
unit = Unit maybeUnit;
|
|
prefix
|
|
= if unit.prefix != null
|
|
&& unit.prefix != ""
|
|
then
|
|
"\\acrshort{${unit.prefix}}"
|
|
else
|
|
"";
|
|
link
|
|
= {
|
|
"gram" = "\\acrtext[kilogram]{g}";
|
|
"calorie" = "\\acrtext[kilocalorie]{cal}";
|
|
}.${unit.unit} or "\\acrshort{${unit.unit}}";
|
|
formated = "\\text{${prefix}${link}}";
|
|
withNumericExponent
|
|
= if unit.exp < 0
|
|
then
|
|
"${formated}^{-\\text{${number.toSignificantString (0 - unit.exp)}}}"
|
|
else
|
|
"${formated}^{\\text{${number.toSignificantString unit.exp}}}";
|
|
sign = formatSign unit.sign;
|
|
in
|
|
if unit != null
|
|
then
|
|
type.matchPrimitiveOrPanic unit.exp
|
|
{
|
|
null = formated;
|
|
int = withNumericExponent;
|
|
float = withNumericExponent;
|
|
string = "${formated}^{${sign}${adjustNumbers unit.exp}}";
|
|
}
|
|
else
|
|
null;
|
|
|
|
parseValue'#: V: ToValue @ [ V ] | V -> Value
|
|
= nested:
|
|
value:
|
|
type.matchPrimitiveOrPanic value
|
|
{
|
|
string
|
|
= let
|
|
parsed = string.match "([-+]|[+][-]|[-][+])?([0-9])[.]?([0-9]*)e?([+-]?)([0-9.]*)" value;
|
|
precision = string.length (list.get parsed 2);
|
|
in
|
|
if parsed != null
|
|
then
|
|
{
|
|
value
|
|
= ( integer "0${list.get parsed 1}" )
|
|
+ ( ( integer "0${list.get parsed 2}" )
|
|
/ ( number.pow 10 precision )
|
|
);
|
|
exp
|
|
= let
|
|
exponent = list.get parsed 4;
|
|
sign = list.get parsed 3;
|
|
in
|
|
if exponent != "" then "${if sign == "-" then "-" else ""}${exponent}"
|
|
else "";
|
|
inherit precision;
|
|
sign = list.get parsed 0;
|
|
}
|
|
else
|
|
{
|
|
inherit value;
|
|
exp = null;
|
|
precision = null;
|
|
sign = null;
|
|
};
|
|
float
|
|
= {
|
|
inherit value;
|
|
exp = null;
|
|
precision = null;
|
|
sign = null;
|
|
};
|
|
int
|
|
= {
|
|
inherit value;
|
|
exp = null;
|
|
precision = 0;
|
|
sign = null;
|
|
};
|
|
set
|
|
= if value ? from
|
|
&& value ? till
|
|
then
|
|
{
|
|
value = { inherit(value) from till; };
|
|
exp = value.exp or null;
|
|
precision = value.precision or null;
|
|
sign = value.sign or null;
|
|
}
|
|
else
|
|
{
|
|
value
|
|
= type.matchPrimitiveOrPanic value.value
|
|
{
|
|
string = value.value;
|
|
float = value.value;
|
|
int = value.value;
|
|
set
|
|
= if value.value ? from
|
|
&& value.value ? till
|
|
then
|
|
value.value
|
|
else
|
|
debug.panic "parseValue'" "from and till expected!";
|
|
list
|
|
= if nested
|
|
then
|
|
list.map (parseValue' false) value.value
|
|
else
|
|
debug.panic "parseValue'" "Set-Value cannot be nested!";
|
|
};
|
|
exp
|
|
= let
|
|
exp = value.exp or null;
|
|
in
|
|
type.matchPrimitiveOrPanic exp
|
|
{
|
|
null = null;
|
|
int = exp;
|
|
float = exp;
|
|
string = exp;
|
|
};
|
|
precision = value.precision or (if integer.isInstanceOf value then 0 else null);
|
|
sign = value.sign or null;
|
|
};
|
|
list
|
|
= if nested
|
|
then
|
|
{
|
|
value = list.map (parseValue' false) value;
|
|
exp = null;
|
|
precision = null;
|
|
sign = null;
|
|
}
|
|
else
|
|
debug.panic "parseValue'" "Lists cannot be nested!";
|
|
};
|
|
|
|
parseValue#: V: ToValue @ [ V ] | V -> Value
|
|
= parseValue' true;
|
|
|
|
formatValue#: V: ToValue, U: ToUnit @ V -> U -> string
|
|
= value:
|
|
unit:
|
|
"\\mbox{\\ensuremath{${formatValueInMath value unit}}}";
|
|
|
|
formatValueInMath#: V: ToValue, U: ToUnit @ V -> U -> string
|
|
= value:
|
|
unit:
|
|
let
|
|
valueText = formatValue' value;
|
|
unitText = formatUnit' unit;
|
|
in
|
|
if unitText != null
|
|
then
|
|
"${valueText}\\,${unitText}"
|
|
else
|
|
valueText;
|
|
|
|
formatValue'#: V: ToValue @ [ V ] | V -> string
|
|
= value:
|
|
let
|
|
value' = parseValue value;
|
|
numeric = number.toStringWithPrecision value'.value value'.precision;
|
|
valueText
|
|
= type.matchPrimitiveOrPanic value'.value
|
|
{
|
|
set
|
|
= let
|
|
text = number.toStringWithPrecision value'.value value'.precision;
|
|
in
|
|
if value'.exp != null
|
|
|| value'.sign != null
|
|
then
|
|
"(${text})"
|
|
else
|
|
text;
|
|
string = "${value'.value}";
|
|
float = numeric;
|
|
int = numeric;
|
|
list
|
|
= let
|
|
text
|
|
= string.concatMappedWith
|
|
(
|
|
{ precision, ... } @ value:
|
|
formatValue'
|
|
(
|
|
if precision != null
|
|
then
|
|
value // { inherit precision; }
|
|
else
|
|
value
|
|
)
|
|
)
|
|
", " value'.value;
|
|
in
|
|
if value'.exp != null
|
|
|| value'.sign != null
|
|
then
|
|
"(${text})"
|
|
else
|
|
text;
|
|
};
|
|
exponentText
|
|
= let
|
|
withNumericExponent
|
|
= if value'.exp < 0
|
|
then
|
|
"-\\text{${number.toSignificantString (0 - value'.exp)}}"
|
|
else
|
|
"\\text{${number.toSignificantString value'.exp}}";
|
|
exponent
|
|
= type.matchPrimitiveOrPanic value'.exp
|
|
{
|
|
null = null;
|
|
int = withNumericExponent;
|
|
float = withNumericExponent;
|
|
string = adjustNumbers value'.exp;
|
|
};
|
|
in
|
|
if exponent != null
|
|
then
|
|
"\\cdot\\text{10}^{${exponent}}"
|
|
else
|
|
"";
|
|
in
|
|
"${formatSign value'.sign}${adjustNumbers valueText}${exponentText}";
|
|
|
|
adjustNumbers
|
|
= this:
|
|
string.concatMapped
|
|
(
|
|
part:
|
|
if list.isInstanceOf part
|
|
then
|
|
"\\text{${list.head part}}"
|
|
else
|
|
part
|
|
)
|
|
(string.split "([0-9]+|[0-9]*[.][0-9]*)" this);
|
|
in
|
|
{ inherit formatValue formatValueInMath formatUnit; } |