using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BaseTypes;
using BaseTypes.Interfaces;
using BaseTypes.CSharp;
using FormulaEditor.CodeCreators;
using FormulaEditor.Interfaces;
namespace FormulaEditor.CSharp
{
/// <summary>
/// Creator of C# code
/// </summary>
public class CSharpCodeCreator : SeparatorCodeCreator, IOperationSeparatorCreator
{
#region Fields
/// <summary>
/// Singleton
/// </summary>
public static readonly ICodeCreator CodeCreator = new CSharpCodeCreator();
/// <summary>
/// Standard header of calculation class
/// </summary>
public const string StandardHeader = "using System;\r\nusing System.Collections.Generic;\r\nusing System.Text;\r\n\r\n";
private static bool cycle = true;
private static readonly ITypeCreator typeCreator =
new CSTypeCreator();
private static readonly Dictionary<string, string[]> elementary =
new Dictionary<string, string[]> {
{"s", new string[] {" = Math.Sin(", ");"}},
{"c", new string[] {" = Math.Cos(", ");"}},
{"l", new string[] {" = Math.Log(", ");"}},
{"e", new string[] {" = Math.Exp(", ");"}},
{"t", new string[] {" = Math.Tan(", ");"}},
{"q", new string[] {" = Math.Tan( Math.PI / 2 - (", "));"}},
{"a", new string[] {" = Math.Atan(", ");"}},
{"b", new string[] {" = Math.PI / 2 - Math.Atan(", ");"}},
{"j", new string[] {" = 1 / Math.Cos(", ");"}},
{"k", new string[] {" = 1 / Math.Sin(", ");"}},
{"f", new string[] {" = Math.Asin(", ");"}},
{"g", new string[] {" = Math.Acos(", ");"}},
{"?", new string[] {" = (", ");"}},
{"-", new string[] {" = -(", ");"}},
};
private static readonly string[] squareRoot = new string[] { " = Math.Sqrt(", ");" };
private static readonly string[] root = new string[] { " = Math.Pow(", ", 1 /(", "));" };
private static readonly string[] atan2 = new string[] { " = Math.Atan2(", ", ", ");" };
private static readonly string[] optionalSeparator = new string[] {" = (", ") ? (", ") : (", ");"};
private static readonly string[] power = new string[]
{ " = Math.Pow(", ", ", ");" };
private static Dictionary<string, string[]> elementaryBinary = new Dictionary<string, string[]>()
{
{"+", new string[] {" = (", ") + (", ");"}},
{"-", new string[] {" = (", ") - (", ");"}},
{"*", new string[] {" = (", ") * (", ");"}},
};
private static readonly Dictionary<string, string[]> comparation = new Dictionary<string, string[]>()
{
{">", new string[] {" = (", ") > (", ");"}},
{"<", new string[] {" = (", ") < (", ");"}},
{"\u2260", new string[] {" != (", ") * (", ");"}},
{"\u2264", new string[] {" >= (", ") * (", ");"}},
{"\u2265", new string[] {" >= (", ") * (", ");"}},
};
private static readonly Dictionary<string, string[]> logicalOperation = new Dictionary<string, string[]>()
{
{"\u2216", new string[] {" = (", ") & (", ");"}},
{"\u2217", new string[] {" = (", ") | (", ");"}}
};
private static string[] fraction = new string[] { " = (", ") / (", ");" };
#endregion
#region Ctor
private CSharpCodeCreator()
: this(null)
{
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="trees">Trees</param>
protected CSharpCodeCreator(ObjectFormulaTree[] trees)
: base(trees)
{
separatorCreator = this;
}
#endregion
#region Overriden Members
/// <summary>
/// Creates Code from tree
/// </summary>
/// <param name="tree">The tree</param>
/// <param name="ret">Return value</param>
/// <param name="parameters">Parameters</param>
/// <param name="variables">Variables</param>
/// <param name="initializers">Initializers</param>
/// <returns>List of code</returns>
public override IList<string> CreateCode(ObjectFormulaTree tree, string ret, string[] parameters, out IList<string> variables, out IList<string> initializers)
{
IList<string> l = base.CreateCode(tree, ret, parameters, out variables, out initializers);
if (l != null)
{
return l;
}
l = CreateArraySingleCode(tree, ret, parameters, out variables, out initializers);
if (l != null)
{
return l;
}
l = CreateArrayCode(tree, ret, parameters, out variables, out initializers);
if (l != null)
{
return l;
}
return CreateTreeCode(tree, ret, parameters, out variables, out initializers);
}
/// <summary>
/// Gets constant string representation of value of tree
/// </summary>
/// <param name="tree">The tree</param>
/// <returns>String representation</returns>
public override string GetConstValue(ObjectFormulaTree tree)
{
IObjectOperation op = tree.Operation;
if (op is ElementaryRealConstant)
{
ElementaryRealConstant co = op as ElementaryRealConstant;
/* if (!consts.Contains(tree))
{
consts.Add(tree);
}*/
return co.StringValue;
}
return null;
}
#endregion
#region IOperationSeparatorCreator Members
/// <summary>
/// Separators
/// </summary>
/// <param name="tree">Tree</param>
/// <returns>operation separators</returns>
public new virtual string[] this[ObjectFormulaTree tree]
{
get
{
string[] ss = null;
IObjectOperation op = tree.Operation;
ss = GetMultiSeparator(tree.Operation);
if (ss != null)
{
return ss;
}
return null;
}
}
/// <summary>
/// Creates Creator
/// </summary>
/// <param name="trees">Trees</param>
/// <returns>Creator</returns>
public override ICodeCreator Create(ObjectFormulaTree[] trees)
{
return new CSharpCodeCreator(trees);
}
#endregion
#region Members
/// <summary>
/// Creates code
/// </summary>
/// <param name="trees">Trees</param>
/// <param name="creator">Code creator</param>
/// <param name="local">Local code creator</param>
/// <param name="variables">Variables</param>
/// <param name="initializers">Initializers</param>
/// <returns>List of code strings</returns>
public static IList<string> CreateCode(ObjectFormulaTree[] trees, ICodeCreator creator, out ICodeCreator local,
out IList<string> variables, out IList<string> initializers)
{
IList<string> l = StaticCodeCreator.CreateCode(trees, creator, out local,
out variables, out initializers);
variables.Add("ObjectFormulaTree currentTree = null;");
variables.Add("object[] currentArray = null;");
variables.Add("double doubleValue = 0;");
variables.Add("ObjectFormulaTree[] trees = null;");
ObjectFormulaTree[] lt = local.Trees;
foreach (ObjectFormulaTree tree in lt)
{
object ret = tree.ReturnType;
string s = typeCreator.GetType(ret) + " ";
s += local[tree] + " = ";
string cv = creator.GetConstValue(tree);
if (cv == null)
{
s += typeCreator.GetDefaultValue(ret);
}
else
{
s += cv;
}
s += ";";
variables.Add(s);
}
return l;
}
private static string GuidClass
{
get
{
string guid = Guid.NewGuid() + "";
guid = guid.Replace('-', '_');
string ss = "namespace Calculation";
// ss += guid;
ss += "\r\n{\r\n public class Calculate ";
return ss;
}
}
private static string AddType(string s, Type type)
{
string so = s + "";
if (so.Contains(":"))
{
so += ": ";
}
else
{
so += ", ";
}
so += type.FullName;
return so;
}
/// <summary>
/// Create Guid class name
/// </summary>
/// <param name="types">Types of variables</param>
/// <returns>Class name</returns>
public static string GetGuidClass(Type[] types)
{
string s = GuidClass;
if (types != null)
{
if (types.Length > 0)
{
s += ": ";
string ss = "";
foreach (Type t in types)
{
s += t.FullName + ss;
ss = ", ";
}
}
}
s += "\r\n";
s += "{\r\n";
return s;
}
private string[] GetMultiSeparator(IObjectOperation op)
{
/* if (op is OptionalOperation)
{
return optional;
}*/
if (op is ElementaryBinaryOperation)
{
ElementaryBinaryOperation eb = op as ElementaryBinaryOperation;
string seb = eb.Symbol + "";
if (elementaryBinary.ContainsKey(seb))
{
return elementaryBinary[seb];
}
}
if (op is ElementaryAtan2)
{
return atan2;
}
if (op is ElementaryFraction)
{
return fraction;
}
if (op is ElementaryRoot)
{
if (op.Arity == 1)
{
return squareRoot;
}
return root;
}
if (op is ElementaryFunctionOperation)
{
ElementaryFunctionOperation o = op as ElementaryFunctionOperation;
string key = o.Symbol + "";
if (elementary.ContainsKey(key))
{
return elementary[key];
}
}
if (op is ComparationOperation)
{
ComparationOperation co = op as ComparationOperation;
string cos = co.String;
if (comparation.ContainsKey(cos))
{
return comparation[cos];
}
}
if (op is LogicalOperation)
{
LogicalOperation lo = op as LogicalOperation;
string los = lo.Symbol + "";
if (logicalOperation.ContainsKey(los))
{
return logicalOperation[los];
}
}
if (op is ElementaryPowerOperation)
{
return power;
}
return null;
}
/// <summary>
/// Creates code for array operation
/// </summary>
/// <param name="tree">Tree</param>
/// <param name="ret">Return</param>
/// <param name="parameters">Parameters of tree</param>
/// <param name="variables">Variables</param>
/// <param name="initializers">Initializers</param>
/// <returns>List of code strings</returns>
protected IList<string> CreateArraySingleCode(ObjectFormulaTree tree, string ret, string[] parameters,
out IList<string> variables, out IList<string> initializers)
{
variables = new List<string>();
initializers = new List<string>();
IObjectOperation op = tree.Operation;
if (!(op is ArraySingleOperation))
{
return null;
}
ArraySingleOperation ars = op as ArraySingleOperation;
string ops = (ars.Type == ArraySingleOperationType.Sum) ? " + " : " * ";
ObjectFormulaTree t = tree[0];
ArrayReturnType art = t.ReturnType as ArrayReturnType;
int n = art.Dimension[0];
string sp = "";
if (art.IsObjectType)
{
sp = "(double)";
}
StringBuilder sb = new StringBuilder();
sb.Append(ret);
sb.Append(" = ");
string par = sp + parameters[0] + "[";
sb.Append(par + "0]");
par = ops + par;
for (int i = 1; i < n; i++)
{
sb.Append(par);
sb.Append(i);
sb.Append("]");
}
sb.Append(";");
return new List<string> { { sb.ToString() } };
}
private string GetModifier(object type)
{
string s = "";
if (type is ArrayReturnType)
{
ArrayReturnType art = type as ArrayReturnType;
if (art.IsObjectType)
{
s = "(" + typeCreator.GetType(art.ElementType) + ")";
}
}
return s;
}
private int GetLength(object type)
{
if (!(type is ArrayReturnType))
{
return 0;
}
ArrayReturnType art = type as ArrayReturnType;
return art.Dimension.Length;
}
private int GetMaxLength(object[] types)
{
int n = 0;
foreach (object type in types)
{
int m = GetLength(type);
if (m > n)
{
n = m;
}
}
return n;
}
/// <summary>
/// Creates code from tree
/// </summary>
/// <param name="tree">The tree</param>
/// <param name="ret">Return identifier</param>
/// <param name="parameters">Parameters of tree</param>
/// <param name="variables">Variables of tree</param>
/// <param name="initializers">Initializers</param>
/// <returns>List of code strings</returns>
protected IList<string> CreateArrayCode(ObjectFormulaTree tree, string ret, string[] parameters,
out IList<string> variables, out IList<string> initializers)
{
List<string> vari = new List<string>();
List<string> init = new List<string>();
variables = vari;
initializers = init;
IObjectOperation op = tree.Operation;
if (!(op is ArrayOperation))
{
return null;
}
ArrayOperation ao = op as ArrayOperation;
object[] types = ao.Types;
string[] par = new string[parameters.Length];
for (int i = 0; i < par.Length; i++)
{
par[i] = GetModifier(types[i]) + parameters[i];
}
ArrayReturnType art = ao.ReturnType as ArrayReturnType;
List<ObjectFormulaTree> ch = new List<ObjectFormulaTree>();
for (int i = 0; i < tree.Count; i++)
{
if (tree[i] != null)
{
ch.Add(tree[i]);
}
}
ObjectFormulaTree t = new ObjectFormulaTree(ao.SingleOperation, ch);
List<string> list = new List<string>();
bool success;
if (cycle)
{
ProcessCycleArrayCode(0, tree, t, ret + "[", par, types, art, list, vari, init, out success);
}
else
{
ProcessArrayCode(0, tree, t, ret + "[", par, types, art, list, vari, init, out success);
}
if (!success)
{
return null;
}
return list;
}
/// <summary>
/// Process cyclic array code
/// </summary>
/// <param name="level">Level</param>
/// <param name="baseTree">Base tree</param>
/// <param name="childTree">Child tree</param>
/// <param name="ret">Rerurn</param>
/// <param name="parameters">Parametres</param>
/// <param name="types">Types of variables</param>
/// <param name="retType">Type of return</param>
/// <param name="list">List of code strings</param>
/// <param name="variables">List of variables</param>
/// <param name="initializers">List of initializers</param>
/// <param name="success">The success sign</param>
protected void ProcessCycleArrayCode(int level, ObjectFormulaTree baseTree, ObjectFormulaTree childTree,
string ret, string[] parameters, object[] types, ArrayReturnType retType, List<string> list,
List<string> variables, List<string> initializers, out bool success)
{
if (retType.Dimension.Length == 1)
{
int n = retType.Dimension[level];
string[] par = new string[parameters.Length];
list.Add("for (int i = 0; i < " + n + "; i++)");
list.Add("{");
string si = "i";
string sf = si + "]";
string retLocal = ret + sf;
for (int j = 0; j < parameters.Length; j++)
{
par[j] = parameters[j] + "";
int ll = GetLength(types[j]);
if (ll > 0)
{
if (ll == 1)
{
par[j] += "[";
}
par[j] += sf;
}
}
IList<string> vari;
IList<string> init;
IList<string> l = CreateCode(childTree, retLocal, par, out vari, out init);
success = (l != null);
if (!success)
{
return;
}
list.AddRange(l);
if (vari != null)
{
variables.AddRange(vari);
}
if (init != null)
{
initializers.AddRange(init);
}
list.Add("}");
success = true;
return;
}
if (level == retType.Dimension.Length - 1)
{
int n = retType.Dimension[level];
string[] par = new string[parameters.Length];
for (int i = 0; i < n; i++)
{
string si = i + "";
string sf = si + "]";
string retLocal = ret + sf;
for (int j = 0; j < parameters.Length; j++)
{
par[j] = parameters[j] + "";
int ll = GetLength(types[j]);
if (ll > 0)
{
if (ll == 1)
{
par[j] += "[";
}
par[j] += sf;
}
}
IList<string> vari;
IList<string> init;
IList<string> l = CreateCode(childTree, retLocal, par, out vari, out init);
success = (l != null);
if (!success)
{
return;
}
list.AddRange(l);
if (vari != null)
{
variables.AddRange(vari);
}
if (init != null)
{
initializers.AddRange(init);
}
}
success = true;
return;
}
string[] localPar = new string[parameters.Length];
int k = retType.Dimension[level];
int length = retType.Dimension.Length;
for (int i = 0; i < k; i++)
{
string[] parlocal = new string[parameters.Length];
string retLocal = ret + i + ",";
for (int j = 0; j < parameters.Length; i++)
{
int dim = GetLength(types[j]);
if (dim == 0)
{
continue;
}
if ((dim + level) <= length)
{
continue;
}
if ((dim + level) == length)
{
parlocal[i] += "[" + i + ", ";
continue;
}
parlocal[i] += i + ",";
}
ProcessArrayCode(level + 1, baseTree, childTree, retLocal, parlocal, types,
retType, list, variables, initializers, out success);
if (!success)
{
return;
}
}
success = true;
}
/// <summary>
/// Processes array code
/// </summary>
/// <param name="level">Level</param>
/// <param name="baseTree">Base tree</param>
/// <param name="childTree">Current tree</param>
/// <param name="ret">Return</param>
/// <param name="parameters">Parameters</param>
/// <param name="types">Types of variables</param>
/// <param name="retType">Return type</param>
/// <param name="list">List of code strings</param>
/// <param name="variables">Variables</param>
/// <param name="initializers">Initializers</param>
/// <param name="success">The "success" sign</param>
protected void ProcessArrayCode(int level, ObjectFormulaTree baseTree, ObjectFormulaTree childTree,
string ret, string[] parameters, object[] types, ArrayReturnType retType, List<string> list,
List<string> variables, List<string> initializers, out bool success)
{
if (level == retType.Dimension.Length - 1)
{
int n = retType.Dimension[level];
string[] par = new string[parameters.Length];
for (int i = 0; i < n; i++)
{
string si = i + "";
string sf = si + "]";
string retLocal = ret + sf;
for (int j = 0; j < parameters.Length; j++)
{
par[j] = parameters[j] + "";
int ll = GetLength(types[j]);
if (ll > 0)
{
if (ll == 1)
{
par[j] += "[";
}
par[j] += sf;
}
}
IList<string> vari;
IList<string> init;
IList<string> l = CreateCode(childTree, retLocal, par, out vari, out init);
success = (l != null);
if (!success)
{
return;
}
list.AddRange(l);
if (vari != null)
{
variables.AddRange(vari);
}
if (init != null)
{
initializers.AddRange(init);
}
}
success = true;
return;
}
string[] localPar = new string[parameters.Length];
int k = retType.Dimension[level];
int length = retType.Dimension.Length;
for (int i = 0; i < k; i++)
{
string[] parlocal = new string[parameters.Length];
string retLocal = ret + i + ",";
for (int j = 0; j < parameters.Length; i++)
{
int dim = GetLength(types[j]);
if (dim == 0)
{
continue;
}
if ((dim + level) <= length)
{
continue;
}
if ((dim + level) == length)
{
parlocal[i] += "[" + i + ", ";
continue;
}
parlocal[i] += i + ",";
}
ProcessArrayCode(level + 1, baseTree, childTree, retLocal, parlocal, types,
retType, list, variables, initializers, out success);
if (!success)
{
return;
}
}
success = true;
}
/// <summary>
/// Creates array code
/// </summary>
/// <param name="tree">Base tree</param>
/// <param name="ret">Return</param>
/// <param name="parameters">Variables</param>
/// <param name="variables">Parameters</param>
/// <param name="initializers">Initializers</param>
/// <returns>List of code strings</returns>
protected IList<string> CreateTreeCode(ObjectFormulaTree tree, string ret, string[] parameters,
out IList<string> variables, out IList<string> initializers)
{
List<string> l = new List<string>();
int n = StaticCodeCreator.GetNumber(this, tree);
l.Add("\t\t\tcurrentTree = trees[" + n + "];");
int count = tree.Count;
List<string> vari = new List<string>();
string ta = "treeArray_" + n;
l.Add("\t\t\tcurrentArray = " + ta + ";");
vari.Add("object[] " + ta + " = new object[" + count + "];");
for (int i = 0; i < count; i++)
{
ObjectFormulaTree t = tree[i];
if (t == null)
{
continue;
}
string id = codeCreator[t];
l.Add("currentArray[" + i + "] = " + id + ";");
}
string ss = "";
string tt = typeCreator.GetType(tree.ReturnType);
if (!tt.Equals("object"))
{
ss = "(" + tt + ")";
}
l.Add(ret + " = " + ss + "currentTree.Calculate(currentArray);");
initializers = new List<string>();
variables = vari;
return l;
}
#endregion
}
}