using System; using System.Collections.Generic; namespace DtxCS.DataTypes { /// /// Represents an array of DataNodes. /// public class DataArray : DataNode { public virtual char ClosingChar => ')'; /// /// Returns DataType.ARRAY /// public override DataType Type => DataType.ARRAY; /// /// The children of this array. /// public List Children { get; } /// /// Default constructor for a Data Array. /// public DataArray() { this.Children = new List(); } /// /// Add a node to this Array. /// /// Node to add /// The added node. public T AddNode(T node) where T : DataNode { Children.Add(node); node.Parent = this; return node; } /// /// Get or set the child of this array at the given index. /// /// /// public DataNode this[int index] { get { return Children[index]; } set { Children[index] = value; } } /// /// Find the array in this array's children at the given index. /// /// /// public DataArray Array(int idx) { if (Children[idx].Type == DataType.ARRAY) { return (DataArray)Children[idx]; } throw new Exception("Element at index " + idx + " is not an Array. It is "+Children[idx].GetType().Name); } /// /// Find the integer in this array's children at the given index. /// /// /// public int Int(int idx) { if (Children[idx].Type == DataType.INT) { return ((DataAtom)Children[idx]).Int; } throw new Exception("Element at index " + idx + " is not an integer."); } /// /// Find the float in this array's children at the given index. /// /// /// public float Float(int idx) { if (Children[idx].Type == DataType.FLOAT) { return ((DataAtom)Children[idx]).Float; } throw new Exception("Element at index " + idx + " is not a float."); } public float Number(int idx) { if (Children[idx].Type == DataType.FLOAT) { return ((DataAtom)Children[idx]).Float; } else if (Children[idx].Type == DataType.INT) { return ((DataAtom)Children[idx]).Int; } throw new Exception("Element at index " + idx + " is not a number."); } public DataNode Node(int idx) { return Children[idx]; } /// /// Find the string in this array's children at the given index. /// /// /// public string String(int idx) { if (Children[idx].Type == DataType.STRING) { return ((DataAtom)Children[idx]).String; } throw new Exception("Element at index " + idx + " is not a string."); } /// /// Find the symbol in this array's children at the given index. /// /// /// public DataSymbol Symbol(int idx) { if(Children[idx].Type == DataType.SYMBOL) { return (DataSymbol)Children[idx]; } throw new Exception("Element at index " + idx + " is not a symbol."); } /// /// Find the variable in this array's children at the given index. /// /// /// public DataVariable Var(int idx) { if (Children[idx].Type == DataType.VARIABLE) { return (DataVariable)Children[idx]; } throw new Exception("Element at index " + idx + " is not a variable."); } /// /// Finds any node at the given index and returns it as a string. /// /// /// public string Any(int idx) { return Children[idx].Name; } /// /// Find the first array in this array's children whose name matches. /// If none is found, returns null. /// /// /// public DataArray Array(string name) { for (int i = 0; i < Children.Count; i++) { if (!(Children[i] is DataArray)) continue; if (Children[i].Name == name) { return ((DataArray)Children[i]); } } return null; } public override DataNode Evaluate() { var returnArray = new DataArray(); foreach(var node in Children) { returnArray.AddNode(node.Evaluate()); } return returnArray; } /// /// The string representation of the first element of the array, unless /// that element is another array, which would result in an empty string. /// public override string Name => Children[0].Type == DataType.ARRAY ? "" : Children[0].Name; /// /// The number of elements in this array. /// public int Count => Children.Count; /// /// The string representation of this Array, suitable for putting right /// back into a .dta file. /// /// public override string ToString() => ToString(0); public override string ToString(int depth) { string ret = new string(' ', depth*3) + "("; for (int i = 0; i < Children.Count; i++) { var n = Children[i]; ret += n is DataArray ? Environment.NewLine + n.ToString(depth + 1) : n.ToString(depth + 1); if (i + 1 != Children.Count) ret += " "; } ret += ")"; return ret; } } public class DataCommand : DataArray { public override DataType Type => DataType.COMMAND; public override char ClosingChar => '}'; public DataCommand() : base() { } public override string ToString() => ToString(0); public override string ToString(int depth) { string ret = new string(' ', depth*3)+"{"; foreach (DataNode n in Children) { ret += (n is DataArray ? Environment.NewLine + n.ToString(depth + 1) : n.ToString(depth + 1) + " "); } ret += "}"; return ret; } /// /// Returns a copy of this datacommand with all children evaulated. /// public DataCommand EvalAll() { var ret = new DataCommand(); for(var i = 0; i < Children.Count; i++) { ret.AddNode(Children[i].Evaluate()); } return ret; } public override DataNode Evaluate() { Func f; if (Builtins.Funcs.TryGetValue(Symbol(0), out f)) { return f.Invoke(this); } throw new Exception($"Func '{Any(0)}' is not defined."); } } // e.g., [RED 1 0 0] in a file, then (color RED) -> (color 1 0 0) // or, [TRUE 1] -> (happy TRUE) -> (happy 1) public class DataMacroDefinition : DataArray { public override DataType Type => DataType.MACRO; public override char ClosingChar => ']'; public DataMacroDefinition() : base() { } public override string ToString() => ToString(0); public override DataNode Evaluate() => this; public override string ToString(int depth) { string ret = new string(' ', depth*3) + "["; foreach (DataNode n in Children) { ret += (n is DataArray ? Environment.NewLine + n.ToString(depth + 1) : n.ToString(depth + 1) + " "); } ret += "]"; return ret; } } }