using System; using System.Collections.Generic; namespace DtxCS.DataTypes { /// /// The most basic element of dta. /// public class DataAtom : DataNode { DataType type; string sData; int iData; float fData; /// /// The type of this Atom. /// public override DataType Type => type; public override DataNode Evaluate() => this; /// /// The value of this Atom. /// public int Int { get { if (type == DataType.INT) return iData; else throw new Exception("Data is not int"); } } /// /// The value of this Atom. /// public float Float { get { if (type == DataType.FLOAT) return fData; else throw new Exception("Data is not float"); } } /// /// The value of this Atom. /// public string String { get { if (type == DataType.STRING) return sData; else throw new Exception("Data is not string"); } } /// /// Construct an Atom whose value is a string or symbol. /// /// The value assigned to this atom. public DataAtom(string data) { type = DataType.STRING; sData = data.Replace("\\q", "\""); } /// /// Construct an Atom whose value is an integer. /// /// public DataAtom(int data) { type = DataType.INT; iData = data; } /// /// Construct an Atom whose value is a floating-point value. /// /// public DataAtom(float data) { type = DataType.FLOAT; fData = data; } /// /// The string representation of this Atom. /// public override string Name => ToString(true); private string ToString(bool name) { string ret = ""; switch (type) { case DataType.STRING: ret += name ? sData : "\"" + sData.Replace("\"", "\\\"") + "\""; break; case DataType.INT: ret += iData.ToString(); break; case DataType.FLOAT: // Even though the format string uses a dot, it gets changed to a comma on some locales // unless you give ToString the invariant culture. ret += fData.ToString("0.0#", System.Globalization.NumberFormatInfo.InvariantInfo); break; } return ret; } /// /// Returns the string representation of this Atom. /// /// public override string ToString() => ToString(false); } public class DataVariable : DataNode { static Dictionary vars = new Dictionary(); public override string Name { get; } public override string ToString() => Name; public override DataType Type => DataType.VARIABLE; public DataNode Value { get; set; } public override DataNode Evaluate() => Value; public static DataVariable Var(string name) { DataVariable ret; if (!vars.TryGetValue(name, out ret)) vars.Add(name, ret = new DataVariable(name, new DataAtom(0))); return ret; } /// /// Makes a data variable. Scoping not implemented because we're not an interpreter. /// Don't give this the $. /// /// private DataVariable(string name, DataNode value) { Name = "$" + name; Value = value; } } public class DataSymbol : DataNode { static Dictionary symbols = new Dictionary(); public static DataSymbol Symbol(string value) { DataSymbol ret; if (!symbols.TryGetValue(value, out ret)) symbols.Add(value, ret = new DataSymbol(value)); return ret; } public override string Name => value; public override DataNode Evaluate() => this; public override DataType Type => DataType.SYMBOL; private string value; private bool quote; private DataSymbol(string value) { this.value = value; foreach(var c in value) { // TODO: Is this right? if(c == ' ' || c == '\r' || c == '\n' || c == '\t' || c == '(' || c == ')' || c == '{' || c == '}' || c == '[' || c == ']') { quote = true; break; } } } public override string ToString() => quote ? $"'{Name}'" : Name; } }