using System; using NTERA.Engine.Compiler; namespace NTERA.Engine { public enum ValueType { Real, String } public struct Value { public ValueType Type { get; set; } public double Real { get; } public string String { get; } public Value(bool boolean) : this(boolean ? 1d : 0d) { } public Value(double real) : this() { Type = ValueType.Real; Real = real; String = real.ToString("N"); } public Value(string str) : this() { Type = ValueType.String; String = str; Real = Double.NaN; } public Value Operate(Value b, Token tok) { Value a = this; bool isStringOperation = a.Type == ValueType.String || b.Type == ValueType.String; if (isStringOperation) { switch (tok) { case Token.Plus: return new Value(a.String + b.String); case Token.Equal: return new Value(a.String == b.String); case Token.NotEqual: return new Value(a.String != b.String); } } else { switch (tok) { case Token.Plus: return new Value(a.Real + b.Real); case Token.Equal: return new Value(a.Real == b.Real); case Token.NotEqual: return new Value(a.Real != b.Real); case Token.Minus: return new Value(a.Real - b.Real); case Token.Asterisk: return new Value(a.Real * b.Real); case Token.Slash: return new Value(a.Real / b.Real); case Token.Caret: return new Value(Math.Pow(a.Real, b.Real)); case Token.Less: return new Value(a.Real < b.Real ? 1 : 0); case Token.More: return new Value(a.Real > b.Real ? 1 : 0); case Token.LessEqual: return new Value(a.Real <= b.Real ? 1 : 0); case Token.MoreEqual: return new Value(a.Real >= b.Real ? 1 : 0); } } throw new Exception($"Invalid operation on value ({tok}) on {(isStringOperation ? "string" : "double")}"); } public static Value operator +(Value value1, Value value2) { return value1.Operate(value2, Token.Plus); } public override string ToString() { return String; } public static implicit operator double(Value value) { return value.Real; } public static implicit operator string(Value value) { return value.String; } public static implicit operator bool(Value value) { return value.Real != 0; } public static implicit operator Value(double value) { return new Value(value); } public static implicit operator Value(string value) { return new Value(value); } public static implicit operator Value(bool value) { return new Value(value); } } }