public (object, KalkExpression) Canonical(KalkExpression value) { Collect(value); SquashPowers(); // Compute the final canonical value KalkExpression leftValue = null; if (_powers != null) { for (var i = 0; i < _powers.Count; i++) { var power = _powers[i]; var powerValue = _context.ToObject <double>(_context.CurrentSpan, power.Unit); if (powerValue < 0) { powerValue = -powerValue; power.Unit = powerValue; object left = leftValue ?? (object)1.0; leftValue = new KalkBinaryExpression(left, ScriptBinaryOperator.Divide, KalkValue.AlmostEqual(powerValue, 1.0) ? power.Value : power); } else { var nextMul = KalkValue.AlmostEqual(powerValue, 1.0) ? (KalkUnit)power.Value : (KalkExpression)power; leftValue = leftValue == null ? nextMul : new KalkBinaryExpression(leftValue, ScriptBinaryOperator.Multiply, nextMul); } } } return(_value, leftValue); }
public static bool Equals(TemplateContext context, KalkExpression left, KalkExpression right) { if (ReferenceEquals(null, right)) { return(false); } if (ReferenceEquals(left, right)) { return(true); } return(right.GetType() == left.GetType() && left.EqualsImpl(context, right)); }
public KalkExpression ConvertTo(TemplateContext context, KalkExpression dst) { var src = this; var destExpr = dst.OriginalExpression ?? dst; var span = context.CurrentSpan; if (!this.TryEvaluate(context, span, ScriptBinaryOperator.Divide, span, this, span, dst, out var result) || result is KalkExpression) { throw new ScriptRuntimeException(context.CurrentSpan, $"Cannot convert the expression {src} to the unit `{destExpr}`. Units are not matching."); } var value = context.ToObject <double>(span, result); return(new KalkBinaryExpression(value, ScriptBinaryOperator.Multiply, dst.OriginalExpression)); }
protected abstract bool EqualsImpl(TemplateContext context, KalkExpression right);
private static ScriptRuntimeException NotMatching(SourceSpan leftSpan, KalkExpression leftExpr, SourceSpan rightSpan, KalkExpression rightExpr) { return(new ScriptRuntimeException(leftExpr == null ? leftSpan : rightSpan, $"Missing unit for the {(leftExpr == null ? "left" : "right")} expression. It must match the unit of the other expression `{leftExpr ?? rightExpr}`.")); }
public KalkExpression ConvertTo(KalkExpression src, KalkExpression dst) { return(src.ConvertTo(this, dst)); }
public KalkExpression RegisterUnit(KalkUnit unit, string description = null, string symbol = null, KalkExpression value = null, string plural = null, string prefix = null, bool isUser = false) { if (unit == null) { throw new ArgumentNullException(nameof(unit)); } var name = unit.Name; symbol ??= name; // Override isUser if (_registerAsSystem) { isUser = false; } CheckVariableAvailable(name, nameof(name), false); var prefixList = new List <KalkUnitPrefix>(); if (prefix != null) { var prefixes = prefix.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (var prefixItem in prefixes) { if (prefixItem == "decimal") { prefixList.AddRange(KalkUnitPrefix.GetDecimals()); } else if (prefixItem == "binary") { prefixList.AddRange(KalkUnitPrefix.GetBinaries()); } else if (KalkUnitPrefix.TryGet(prefixItem, out var descriptor)) { prefixList.Add(descriptor); } else { throw new ArgumentException($"The prefix `{prefixItem}` does not exist.", nameof(prefix)); } } prefixList = prefixList.Distinct().ToList(); } // Pre-check all prefix with name/symbol foreach (var prefixDesc in prefixList) { var prefixWithName = $"{prefixDesc.Name}{name}"; CheckVariableAvailable(prefixWithName, nameof(name), false); var prefixWithSymbol = $"{prefixDesc.Prefix}{symbol}"; CheckVariableAvailable(prefixWithSymbol, nameof(name), false); } unit.Description = description; unit.Symbol = symbol; unit.Value = value; unit.IsUser = isUser; unit.Prefix = prefix; if (plural != null) { unit.Plural = plural; } if (unit.Symbol != unit.Name) { CheckVariableAvailable(unit.Symbol, nameof(symbol), false); } if (unit.Plural != unit.Name) { CheckVariableAvailable(unit.Plural, nameof(plural), false); } // Here we are all done after checking everything Units.Add(name, unit); if (unit.Symbol != unit.Name) { Units.Add(unit.Symbol, unit); } if (unit.Plural != unit.Name) { Units.Add(unit.Plural, unit); } // Register prefixes foreach (var prefixDesc in prefixList) { var prefixWithName = $"{prefixDesc.Name}{unit.Name}"; var prefixWithSymbol = $"{prefixDesc.Prefix}{unit.Symbol}"; var unitPrefix = new KalkUnit(prefixWithName) { Description = description, Symbol = prefixWithSymbol, Value = new KalkBinaryExpression(Math.Pow(prefixDesc.Base, prefixDesc.Exponent), ScriptBinaryOperator.Multiply, unit), IsUser = isUser, Parent = unit, }; unit.Derived.Add(unitPrefix); Units.Add(prefixWithName, unitPrefix); Units.Add(prefixWithSymbol, unitPrefix); } return(unit); }
public KalkExpression DefineUserUnit(ScriptVariable name, string description = null, ScriptVariable symbol = null, KalkExpression value = null, string plural = null, string prefix = null) { if (name == null || string.IsNullOrEmpty(name.Name)) { throw new ArgumentNullException(nameof(name)); } return(RegisterUnit(new KalkUnit(name.Name), description, symbol?.Name, value, plural, prefix, isUser: true)); }