/// Dedicated to the public domain by Christopher Diggins /// http://creativecommons.org/licenses/publicdomain/ using System; using System.Collections.Generic; using System.Text; using System.Diagnostics; namespace Cat { public class Optimizer { /// /// This is a simple yet effective combination of optimizations. /// static public QuotedFunction Optimize(INameLookup names, QuotedFunction qf) { //qf = ApplyMacros(qf); //qf = ApplyMacros(qf); //qf = Expand(qf); //qf = ApplyMacros(qf); //qf = PartialEval(qf); //qf = Expand(qf); //qf = ReplaceSimpleQuotations(qf); qf = ApplyMacros(names, qf); qf = ExpandInline(qf, 4); qf = ApplyMacros(names, qf); return qf; } #region partial evaluation public static Function ValueToFunction(Object o) { if (o is Int32) { return new PushInt((int)o); } else if (o is Double) { return new PushValue((double)o); } else if (o is String) { return new PushValue((string)o); } else if (o is Boolean) { bool b = (bool)o; if (b) return new Primitives.True(); else return new Primitives.False(); } else if (o is CatList) { return new PushValue(o as CatList); } else if (o is QuotedFunction) { QuotedFunction qf = o as QuotedFunction; CatExpr fxns = qf.GetSubFxns(); PushFunction q = new PushFunction(fxns); return q; } else { throw new Exception("Partial evaluator does not yet handle objects of type " + o); } } /// /// This will reduce an expression by evaluating as much at compile-time as possible. /// public static QuotedFunction PartialEval(QuotedFunction qf) { Executor exec = new Executor(); return new QuotedFunction(PartialEval(exec, qf.GetSubFxns())); } /// /// We attempt to execute an expression (list of functions) on an empty stack. /// When no exception is raised we know that the subexpression can be replaced with anything /// that generates the values. /// static CatExpr PartialEval(Executor exec, CatExpr fxns) { // Recursively partially evaluate all quotations for (int i = 0; i < fxns.Count; ++i) { Function f = fxns[i]; if (f is PushFunction) { PushFunction q = f as PushFunction; CatExpr tmp = PartialEval(new Executor(), q.GetSubFxns()); fxns[i] = new PushFunction(tmp); } } CatExpr ret = new CatExpr(); object[] values = null; int j = 0; while (j < fxns.Count) { try { Function f = fxns[j]; if (f is DefinedFunction) { f.Eval(exec); } else { if (f.GetFxnType() == null) throw new Exception("no type availables"); if (f.GetFxnType().HasSideEffects()) throw new Exception("can't perform partial execution when an expression has side-effects"); f.Eval(exec); } // at each step, we have to get the values stored so far // since they could keep changing and any exception // will obliterate the old values. values = exec.GetStackAsArray(); } catch { if (values != null) { // Copy all of the values from the previous good execution for (int k = values.Length - 1; k >= 0; --k) ret.Add(ValueToFunction(values[k])); } ret.Add(fxns[j]); exec.Clear(); values = null; } j++; } if (values != null) for (int l = values.Length - 1; l >= 0; --l) ret.Add(ValueToFunction(values[l])); return ret; } #endregion #region inline expansion static public QuotedFunction ExpandInline(QuotedFunction f, int nMaxDepth) { CatExpr ret = new CatExpr(); ExpandInline(ret, f, nMaxDepth); return new QuotedFunction(ret); } static void ExpandInline(CatExpr list, Function f, int nMaxDepth) { if (nMaxDepth == 0) { list.Add(f); } else if (f is PushFunction) { ExpandInline(list, f as PushFunction, nMaxDepth); } else if (f is QuotedFunction) { ExpandInline(list, f as QuotedFunction, nMaxDepth); } else if (f is DefinedFunction) { ExpandInline(list, f as DefinedFunction, nMaxDepth); } else { list.Add(f); } } static void ExpandInline(CatExpr fxns, PushFunction q, int nMaxDepth) { CatExpr tmp = new CatExpr(); foreach (Function f in q.GetChildren()) ExpandInline(tmp, f, nMaxDepth - 1); fxns.Add(new PushFunction(tmp)); } static void ExpandInline(CatExpr fxns, QuotedFunction q, int nMaxDepth) { foreach (Function f in q.GetSubFxns()) ExpandInline(fxns, f, nMaxDepth - 1); } static void ExpandInline(CatExpr fxns, DefinedFunction d, int nMaxDepth) { foreach (Function f in d.GetSubFxns()) ExpandInline(fxns, f, nMaxDepth - 1); } #endregion #region apply macros static public QuotedFunction ApplyMacros(INameLookup names, QuotedFunction f) { CatExpr list = new CatExpr(f.GetSubFxns().ToArray()); MetaCat.ApplyMacros(names, list); return new QuotedFunction(list); } #endregion } }