public override CGExpr PEval(PEnv pEnv, bool hasDynamicControl) { CGExpr[] res = PEvalArgs(pEnv, hasDynamicControl); // The static argument positions are those that have args[i] != naError Value[] args = new Value[res.Length]; bool anyStatic = false, allStatic = true; for (int i = 0; i < res.Length; i++) { if (res[i] is CGConst) { args[i] = (res[i] as CGConst).Value; anyStatic = true; } else { args[i] = ErrorValue.naError; // Generalize to dynamic allStatic = false; } } if (!hasDynamicControl) { // This would be wrong, because the called function might contain // volatile functions and in that case should residualize: // if (allStatic) // If all arguments static, just call the SDF // return CGConst.Make(sdfInfo.Apply(args)); // else if (anyStatic) // Specialize if there are static arguments { return(Specialize(res, args)); } // Do nothing if all arguments are dynamic } else { // If under dynamic control reduce to longest static prefix // where the argument values agree. // TODO: This is wrong -- should always specialize when the call is not // recursive ICollection <Value[]> pending = SdfManager.PendingSpecializations(sdfInfo.name); Value[] maxArray = null; int maxCount = 0; foreach (Value[] vs in pending) { int agree = AgreeCount(vs, args); if (agree > maxCount) { maxCount = agree; maxArray = vs; } } if (maxCount > 0) { SetNaInArgs(maxArray, args); return(Specialize(res, args)); } } return(new CGSdfCall(sdfInfo, res)); }
private CGSdfCall Specialize(CGExpr[] res, Value[] args) { FunctionValue fv = new FunctionValue(sdfInfo, args); SdfInfo residualSdf = SdfManager.SpecializeAndCompile(fv); CGExpr[] residualArgs = new CGExpr[fv.Arity]; int j = 0; for (int i = 0; i < args.Length; i++) { if (args[i] == ErrorValue.naError) { residualArgs[j++] = res[i]; } } return(new CGSdfCall(residualSdf, residualArgs)); }
public override void Compile() { int argCount = es.Length - 1; if (es.Length < 1) { LoadErrorValue(ErrorValue.argCountError); } else if (es[0] is CGTextConst) { String name = (es[0] as CGTextConst).value.value; SdfInfo sdfInfo = SdfManager.GetInfo(name); if (sdfInfo == null) { LoadErrorValue(ErrorValue.nameError); } else if (argCount != 0 && argCount != sdfInfo.arity) { LoadErrorValue(ErrorValue.argCountError); } else { ilg.Emit(OpCodes.Ldc_I4, sdfInfo.index); CompileToValueArray(argCount, 1, es); ilg.Emit(OpCodes.Call, FunctionValue.makeMethod); } } else { es[0].Compile(); CheckType(FunctionValue.type, new Gen(delegate { CompileToValueArray(argCount, 1, es); ilg.Emit(OpCodes.Call, FunctionValue.furtherApplyMethod); }), GenLoadErrorValue(ErrorValue.argTypeError)); } }
public static CGExpr Make(String name, CGExpr[] es) { name = name.ToUpper(); // This switch should agree with the function table in Functions.cs switch (name) { case "+": return(new CGArithmetic2(OpCodes.Add, name, es)); case "*": return(new CGArithmetic2(OpCodes.Mul, name, es)); case "-": return(new CGArithmetic2(OpCodes.Sub, name, es)); case "/": return(new CGArithmetic2(OpCodes.Div, name, es)); case "=": return(CGEqual.Make(es)); case "<>": return(CGNotEqual.Make(es)); case ">": return(new CGGreaterThan(es)); case "<=": return(new CGLessThanOrEqual(es)); case "<": return(new CGLessThan(es)); case ">=": return(new CGGreaterThanOrEqual(es)); // Non-strict, or other special treatment case "AND": return(new CGAnd(es)); case "APPLY": return(new CGApply(es)); case "CHOOSE": return(new CGChoose(es)); case "CLOSURE": return(new CGClosure(es)); case "ERR": return(new CGError(es)); case "EXTERN": return(new CGExtern(es)); case "IF": return(new CGIf(es)); case "NA": if (es.Length == 0) { return(new CGError(ErrorValue.naError)); } else { return(new CGError(ErrorValue.argCountError)); } case "NEG": return(new CGNeg(es)); case "NOT": return(new CGNot(es)); case "OR": return(new CGOr(es)); case "PI": if (es.Length == 0) { return(new CGNumberConst(NumberValue.PI)); } else { return(new CGError(ErrorValue.argCountError)); } case "VOLATILIZE": if (es.Length == 1) { return(es[0]); } else { return(new CGError(ErrorValue.argCountError)); } default: // The general case for most built-in functions with unspecific argument types FunctionInfo functionInfo; if (FunctionInfo.Find(name, out functionInfo)) { return(new CGFunctionCall(functionInfo, es)); } else // May be a sheet-defined function { SdfInfo sdfInfo = SdfManager.GetInfo(name); if (sdfInfo != null) { return(new CGSdfCall(sdfInfo, es)); } else { return(new CGError(ErrorValue.nameError)); } } } }