public CGExtern(CGExpr[] es) : base(es, null) { if (es.Length < 1) { errorValue = ErrorValue.argCountError; } else { CGTextConst nameAndSignatureConst = es[0] as CGTextConst; if (nameAndSignatureConst == null) { errorValue = ErrorValue.argTypeError; } else { try { // This retrieves the method from cache, or creates it: ef = ExternalFunction.Make(nameAndSignatureConst.value.value); if (ef.arity != es.Length - 1) { ef = null; errorValue = ErrorValue.argCountError; } else { resType = FromType(ef.ResType); argTypes = new Typ[ef.arity]; for (int i = 0; i < argTypes.Length; i++) { argTypes[i] = FromType(ef.ArgType(i)); } } } catch (Exception exn) // Covers a multitude of sins { errorValue = ErrorValue.Make(exn.Message); } } } }
public override CGExpr PEval(PEnv pEnv, bool hasDynamicControl) { // When FunctionValue is known, reduce to a CGSdfCall node. // Don't actually call the function (even on constant arguments); could loop. CGExpr[] res = PEvalArgs(pEnv, hasDynamicControl); if (res[0] is CGValueConst) { FunctionValue fv = (res[0] as CGValueConst).Value as FunctionValue; if (fv != null) { CGExpr[] args = new CGExpr[fv.args.Length]; int j = 1; for (int i = 0; i < args.Length; i++) { if (fv.args[i] != ErrorValue.naError) { args[i] = CGConst.Make(fv.args[i]); } else { args[i] = res[j++]; } } return new CGSdfCall(fv.sdfInfo, args); } else { return new CGError(ErrorValue.argCountError); } } else { return new CGApply(res); } }
public override CGExpr PEval(PEnv pEnv, bool hasDynamicControl) { List <CGExpr> res = new List <CGExpr>(); for (int i = 0; i < es.Length; i++) { CGExpr ri = es[i].PEval(pEnv, hasDynamicControl || res.Count > 0); if (ri is CGNumberConst) { // A TRUE operand makes the OR true; a FALSE operand can be ignored if ((ri as CGNumberConst).number.value != 0.0) { return(new CGNumberConst(NumberValue.ONE)); } } else { res.Add(ri); } } // The residual OR consists of the non-constant operands, if any if (res.Count == 0) { return(new CGNumberConst(NumberValue.ZERO)); } else { return(new CGOr(res.ToArray())); } }
public CGExpr[] PEvalArgs(PEnv pEnv, bool hasDynamicControl) { CGExpr[] res = new CGExpr[es.Length]; for (int i = 0; i < es.Length; i++) { res[i] = es[i].PEval(pEnv, hasDynamicControl); } return res; }
public override CGExpr PEval(PEnv pEnv, bool hasDynamicControl) { // When FunctionValue is known, reduce to a CGSdfCall node. // Don't actually call the function (even on constant arguments); could loop. CGExpr[] res = PEvalArgs(pEnv, hasDynamicControl); if (res[0] is CGValueConst) { FunctionValue fv = (res[0] as CGValueConst).Value as FunctionValue; if (fv != null) { CGExpr[] args = new CGExpr[fv.args.Length]; int j = 1; for (int i = 0; i < args.Length; i++) { if (fv.args[i] != ErrorValue.naError) { args[i] = CGConst.Make(fv.args[i]); } else { args[i] = res[j++]; } } return(new CGSdfCall(fv.sdfInfo, args)); } else { return(new CGError(ErrorValue.argCountError)); } } else { return(new CGApply(res)); } }
// Reductions such as 0*e==>0 are a bit dubious when you // consider that e could evaluate to ArgType error or similar: public CGExpr Make(CGExpr[] es) { if (es.Length == 2) { if (op == "+" && es[0].Is(0)) { return es[1]; // 0+e = e } else if ((op == "+" || op == "-") && es[1].Is(0)) { return es[0]; // e+0 = e-0 = e } else if (op == "-" && es[0].Is(0)) { return new CGNeg(new CGExpr[] {es[1]}); // 0-e = -e } else if (op == "*" && (es[0].Is(0) || es[1].Is(0))) { return new CGNumberConst(NumberValue.ZERO); // 0*e = e*0 = 0 (**) } else if (op == "*" && es[0].Is(1)) { return es[1]; // 1*e = e } else if ((op == "*" || op == "/") && es[1].Is(1)) { return es[0]; // e*1 = e/1 = e } else if (op == "^" && (es[0].Is(1) || es[1].Is(1))) { return es[0]; // e^1 = e and also 1^e = 1 (IEEE) } else if (op == "^" && es[1].Is(0)) { return new CGNumberConst(NumberValue.ONE); // e^0 = 1 (IEEE) } } return new CGArithmetic2(opCode, op, es); }
public CGCachedExpr(CGExpr expr, CachedAtom cachedAtom, List <CGCachedExpr> caches) { this.expr = expr; this.cachedAtom = cachedAtom; this.cacheNumber = caches.Count; caches.Add(this); }
public bool AllConstant(CGExpr[] res) { for (int i = 0; i < res.Length; i++) { if (!(res[i] is CGConst)) { return false; } } return true; }
public CGExpr[] PEvalArgs(PEnv pEnv, bool hasDynamicControl) { CGExpr[] res = new CGExpr[es.Length]; for (int i = 0; i < es.Length; i++) { res[i] = es[i].PEval(pEnv, hasDynamicControl); } return(res); }
private Variable numberVar; // If non-null, unwrap to this Number variable // If var==null then numberVar==null public ComputeCell(CGExpr expr, Variable var, FullCellAddr cellAddr) { this.expr = expr; this.var = var; // The output cell's expression is in tail position: if (var == null) { this.expr.NoteTailPosition(); } this.cellAddr = cellAddr; this.numberVar = null; }
public void CallVisitor(FunCall funCall) { CGExpr[] expressions = new CGExpr[funCall.es.Length]; for (int i = 0; i < funCall.es.Length; i++) { funCall.es[i].VisitorCall(this); expressions[i] = result; } result = CGComposite.Make(funCall.function.name, expressions); }
public override void CompileCondition(Gen ifTrue, Gen ifFalse, Gen ifOther) { for (int i = es.Length - 1; i >= 0; i--) { // These declarations are needed to capture rvalues rather than lvalues: CGExpr ei = es[i]; Gen localIfFalse = ifFalse; ifFalse = new Gen(delegate { ei.CompileCondition(ifTrue, localIfFalse, ifOther); }); } ifFalse.Generate(ilg); }
public static CGExpr Make(CGExpr[] es) { if (es.Length == 2) { if (es[0].Is(0)) // 0.0<>e1 ==> AND(e1) { return new CGAnd(new CGExpr[] {es[1]}); } else if (es[1].Is(0)) // e0<>0.0 ==> AND(e0) { return new CGAnd(new CGExpr[] {es[0]}); } } return new CGNotEqual(es); }
public static CGExpr Make(CGExpr[] es) { if (es.Length == 2) { if (es[0].Is(0)) // 0.0=e1 ==> NOT(e1) { return new CGNot(new CGExpr[] {es[1]}); } else if (es[1].Is(0)) // e0=0.0 ==> NOT(e0) { return new CGNot(new CGExpr[] {es[0]}); } } return new CGEqual(es); }
// This is used to implement the ERR function public CGError(CGExpr[] es) { if (es.Length != 1) { errorValue = ErrorValue.argCountError; } else { CGTextConst messageConst = es[0] as CGTextConst; if (messageConst == null) { errorValue = ErrorValue.argTypeError; } else { errorValue = ErrorValue.Make("#ERR: " + messageConst.value.value); } } }
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 EvalCond(PathCond evalCond, IDictionary <FullCellAddr, PathCond> evalConds, List <CGCachedExpr> caches) { if (es.Length >= 1) { CachedAtom atom = new CachedAtom(es[0], caches); CGCachedExpr cached = atom.cachedExpr; es[0].EvalCond(evalCond, evalConds, caches); es[0] = cached; for (int i = 1; i < es.Length; i++) { CGExpr iConst = CGConst.Make(i); CGExpr cond = new CGEqual(new CGExpr[] { cached, iConst }); es[i].EvalCond(evalCond.And(new CachedAtom(cond, caches)), evalConds, caches); } } }
public void CallVisitor(CellRef cellRef) { FullCellAddr cellAddr = cellRef.GetAbsoluteAddr(thisFca); if (cellAddr.sheet != thisFca.sheet) { // Reference to other sheet, hopefully a normal sheet result = new CGNormalCellRef(cellAddr); } else if (this.addressToVariable.ContainsKey(cellAddr)) { // Reference to a cell that has already been computed in a local variable result = new CGCellRef(cellAddr, this.addressToVariable[cellAddr]); } else // Inline the cell's formula's expression { result = BuildExpression(cellAddr, addressToVariable); } }
/// <summary> /// Compiles the topologically sorted list of Expr to a list (program) /// of ComputeCells, encapsulating CGExprs. Builds a map from cellAddr to /// local variable ids, for compiling sheet-internal cellrefs to ldloc instructions. /// </summary> public void AddComputeCells(DependencyGraph dpGraph, IList <FullCellAddr> cellList) { Debug.Assert(dpGraph.outputCell == cellList[cellList.Count - 1]); CGExpr outputExpr; if (cellList.Count == 0 || cellList.Count == 1 && dpGraph.inputCellSet.Contains(cellList.Single())) { // The output cell is also an input cell; load it: outputExpr = new CGCellRef(dpGraph.outputCell, addressToVariable[dpGraph.outputCell]); } else { // First process all non-output cells, and ignore all input cells: foreach (FullCellAddr cellAddr in cellList) { if (cellAddr.Equals(dpGraph.outputCell)) { continue; } HashSet <FullCellAddr> dependents = dpGraph.GetDependents(cellAddr); int minUses = dependents.Count; if (minUses == 1) { FullCellAddr fromFca = dependents.First(); minUses = Math.Max(minUses, GetCount(fromFca, cellAddr)); } // Now if minUses==1 then there is at most one use of the cell at cellAddr, // and no local variable is needed. Otherwise, allocate a local variable: if (minUses > 1) { CGExpr newExpr = CGExpressionBuilder.BuildExpression(cellAddr, addressToVariable); Variable var = new LocalVariable(cellAddr.ToString(), newExpr.Type()); AddComputeCell(cellAddr, new ComputeCell(newExpr, var, cellAddr)); } } // Then process the output cell: outputExpr = CGExpressionBuilder.BuildExpression(dpGraph.outputCell, addressToVariable); } // Add the output cell expression last, without a variable to bind it to; hence the null, // also indicating that (only) the output cell is in tail position: AddComputeCell(dpGraph.outputCell, new ComputeCell(outputExpr, null, dpGraph.outputCell)); }
public override CGExpr PEval(PEnv pEnv, bool hasDynamicControl) { CGExpr r0 = es[0].PEval(pEnv, hasDynamicControl); if (r0 is CGNumberConst) { if ((r0 as CGNumberConst).number.value != 0.0) { return(es[1].PEval(pEnv, hasDynamicControl)); } else { return(es[2].PEval(pEnv, hasDynamicControl)); } } else { return(new CGIf(PEvalArgs(pEnv, r0, true))); } }
public override CGExpr PEval(PEnv pEnv, bool hasDynamicControl) { CGExpr r0 = es[0].PEval(pEnv, hasDynamicControl); if (r0 is CGNumberConst) { int index = (int)((r0 as CGNumberConst).number.value); if (index < 1 || index >= es.Length) { return(new CGError(ErrorValue.valueError)); } else { return(es[index].PEval(pEnv, hasDynamicControl)); } } else { return(new CGChoose(PEvalArgs(pEnv, r0, true /* has dynamic control */))); } }
// Returns residual ComputeCell or null if no cell needed public ComputeCell PEval(PEnv pEnv) { CGExpr rCond = null; if (evalCond != null) // Never the case for an output cell { rCond = evalCond.PEval(pEnv, false /* not dynamic control */); } if (rCond is CGNumberConst) { if ((rCond as CGNumberConst).number.value != 0.0) { rCond = null; // eval cond constant TRUE, discard eval cond } else { return(null); // eval cond constant FALSE, discard entire compute cell } } // If residual eval cond is not TRUE then expr has dynamic control CGExpr rExpr = expr.PEval(pEnv, rCond != null); if (rExpr is CGConst && var != null) { // If cell's value is constant and it is not an output cell just put in PEnv pEnv[cellAddr] = rExpr; return(null); } else { // Else create fresh local variable for the residual cell, and make // PEnv map cell address to that local variable: Variable newVar = var != null?var.Fresh() : null; pEnv[cellAddr] = new CGCellRef(cellAddr, newVar); ComputeCell result = new ComputeCell(rExpr, newVar, cellAddr); // result.EvalCond = rCond; // Don't save residual eval cond, we compute it accurately later... return(result); } }
public CGSdfCall(SdfInfo sdfInfo, CGExpr[] es) : base(es, null) { this.sdfInfo = sdfInfo; }
public void CallVisitor(CellArea cellArea) { result = new CGNormalCellArea(cellArea.MakeArrayView(thisFca)); }
public override CGExpr Residualize(CGExpr[] res) { return new CGGreaterThan(res); }
// Generate code to evaluate all argument expressions, including the receiver es[1] // if the method is an instance method, and convert their values to .NET types. private void CompileArgumentsAndApply(CGExpr[] es, Gen ifSuccess, Gen ifOther) { int argCount = es.Length; // The error continuations must pop the arguments computed so far. Gen[] errorCont = new Gen[argCount]; if (argCount > 0) { errorCont[0] = ifOther; } for (int i = 1; i < argCount; i++) { int ii = i; // Capture lvalue -- do NOT inline! errorCont[ii] = new Gen(delegate { ilg.Emit(OpCodes.Pop); errorCont[ii - 1].Generate(ilg); }); } // Generate code, backwards, to evaluate argument expressions and // convert to the .NET method's argument types for (int i = argCount - 1; i >= 0; i--) { // These local vars capture rvalue rather than lvalue -- do NOT inline them! CGExpr ei = es[i]; Gen localSuccess = ifSuccess; Typ argType = functionInfo.signature.argTypes[i]; Gen ifError = errorCont[i]; if (argType == Typ.Number) { ifSuccess = new Gen(delegate { ei.CompileToDoubleOrNan(); localSuccess.Generate(ilg); }); } else if (argType == Typ.Function) { ifSuccess = new Gen(delegate { ei.Compile(); CheckType(FunctionValue.type, localSuccess, ifError); }); } else if (argType == Typ.Array) { ifSuccess = new Gen(delegate { ei.Compile(); CheckType(ArrayValue.type, localSuccess, ifError); }); } else if (argType == Typ.Text) { ifSuccess = new Gen(delegate { ei.Compile(); CheckType(TextValue.type, localSuccess, ifError); }); } else // argType.Value -- TODO: neglects to propagate ErrorValue from argument { ifSuccess = new Gen(delegate { ei.Compile(); localSuccess.Generate(ilg); }); } } ifSuccess.Generate(ilg); }
public void CallVisitor(ValueConst valueConst) { result = new CGValueConst(valueConst.value); }
// Generate code to evaluate all argument expressions, including the receiver es[1] // if the method is an instance method, and convert their values to .NET types. private void CompileArgumentsAndApply(CGExpr[] es, Gen ifSuccess, Gen ifOther) { int argCount = es.Length - 1; // The error continuations must pop the arguments computed so far: Gen[] errorCont = new Gen[argCount]; if (argCount > 0) { errorCont[0] = ifOther; } for (int i = 1; i < argCount; i++) { int ii = i; // Capture lvalue -- do NOT inline! errorCont[ii] = new Gen(delegate { ilg.Emit(OpCodes.Pop); errorCont[ii - 1].Generate(ilg); }); } // Generate code, backwards, to evaluate argument expressions and // convert to external method's argument types for (int i = argCount - 1; i >= 0; i--) { // These local vars capture rvalue rather than lvalue -- do NOT inline them! CGExpr ei = es[i + 1]; Gen localSuccess = ifSuccess; int argIndex = i; Type argType = ef.ArgType(i); Gen ifError = errorCont[i]; // First some special cases to avoid boxing: if (argType == typeof (System.Double)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleOrNan(); localSuccess.Generate(ilg); }); } else if (argType == typeof (System.Single)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleOrNan(); ilg.Emit(OpCodes.Conv_R4); localSuccess.Generate(ilg); }); } else if (signed32.Contains(argType)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_I4); localSuccess.Generate(ilg); }), ifError); }); } else if (unsigned32.Contains(argType)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_U4); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof (System.Int64)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_I8); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof (System.UInt64)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_U8); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof (System.Boolean)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Ldc_R8, 0.0); ilg.Emit(OpCodes.Ceq); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof (System.Char)) { ifSuccess = new Gen( delegate { ei.Compile(); ilg.Emit(OpCodes.Call, TextValue.toNakedCharMethod); localSuccess.Generate(ilg); }); } else if (argType == typeof (System.String)) { ifSuccess = new Gen( delegate { ei.Compile(); UnwrapToString(localSuccess, ifError); }); } else // General cases: String[], double[], double[,], ... { ifSuccess = new Gen( delegate { ei.Compile(); ilg.Emit(OpCodes.Call, ef.ArgConverter(argIndex).Method); if (argType.IsValueType) // must unbox wrapped value type, but this is too simple-minded { ilg.Emit(OpCodes.Unbox, argType); } localSuccess.Generate(ilg); }); } } ifSuccess.Generate(ilg); }
public void CallVisitor(TextConst textConst) { result = new CGTextConst(textConst.value); }
public CGLessThanOrEqual(CGExpr[] es) : base(es, leApplier) { }
public void CallVisitor(Error error) { result = new CGError(error.value); }
public CGStrictOperation(CGExpr[] es, Applier applier) : base(es) { this.applier = applier; }
public void CallVisitor(NumberConst numbConst) { result = new CGNumberConst(numbConst.value); }
public override CGExpr Residualize(CGExpr[] res) { return Make(res); }
public CGLessThan(CGExpr[] es) : base(es, ltApplier) { }
public CGEqual(CGExpr[] es) : base(es, eqApplier) { }
/// <summary> /// Generates code to evaluate each expression es[sourceOffset,...] and /// store it into array vs[0,...] on the stack top. /// Assumes an array vs of type Value[] is on the stack, and leaves array vs there. /// </summary> /// <param name="offset">The number of given argument expressions to ignore</param> /// <param name="es">The given (partial) argument expressions</param> internal static void CompileExpressionsAndStore(int sourceOffset, CGExpr[] es) { for (int i = sourceOffset; i < es.Length; i++) { ilg.Emit(OpCodes.Dup); ilg.Emit(OpCodes.Ldc_I4, i - sourceOffset); es[i].Compile(); ilg.Emit(OpCodes.Stelem_Ref); } }
public readonly bool negated; // True if represents NOT(cachedExpr) public CachedAtom(CGExpr cond, List <CGCachedExpr> caches) { this.cachedExpr = new CGCachedExpr(cond, this, caches); this.negated = false; }
public abstract CGExpr Residualize(CGExpr[] res);
public CGCachedExpr(CGExpr expr, CachedAtom cachedAtom, List<CGCachedExpr> caches) { this.expr = expr; this.cachedAtom = cachedAtom; this.cacheNumber = caches.Count; caches.Add(this); }
public override CGExpr Residualize(CGExpr[] res) { return new CGNot(res); }
public override CGExpr Residualize(CGExpr[] res) { return new CGLessThan(res); }
public CGNot(CGExpr[] es) : base(es, notApplier) { }
public CGGreaterThanOrEqual(CGExpr[] es) : base(es, geApplier) { }
// Generate code to evaluate all argument expressions, including the receiver es[1] // if the method is an instance method, and convert their values to .NET types. private void CompileArgumentsAndApply(CGExpr[] es, Gen ifSuccess, Gen ifOther) { int argCount = es.Length - 1; // The error continuations must pop the arguments computed so far: Gen[] errorCont = new Gen[argCount]; if (argCount > 0) { errorCont[0] = ifOther; } for (int i = 1; i < argCount; i++) { int ii = i; // Capture lvalue -- do NOT inline! errorCont[ii] = new Gen(delegate { ilg.Emit(OpCodes.Pop); errorCont[ii - 1].Generate(ilg); }); } // Generate code, backwards, to evaluate argument expressions and // convert to external method's argument types for (int i = argCount - 1; i >= 0; i--) { // These local vars capture rvalue rather than lvalue -- do NOT inline them! CGExpr ei = es[i + 1]; Gen localSuccess = ifSuccess; int argIndex = i; Type argType = ef.ArgType(i); Gen ifError = errorCont[i]; // First some special cases to avoid boxing: if (argType == typeof(System.Double)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleOrNan(); localSuccess.Generate(ilg); }); } else if (argType == typeof(System.Single)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleOrNan(); ilg.Emit(OpCodes.Conv_R4); localSuccess.Generate(ilg); }); } else if (signed32.Contains(argType)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_I4); localSuccess.Generate(ilg); }), ifError); }); } else if (unsigned32.Contains(argType)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_U4); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof(System.Int64)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_I8); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof(System.UInt64)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_U8); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof(System.Boolean)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Ldc_R8, 0.0); ilg.Emit(OpCodes.Ceq); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof(System.Char)) { ifSuccess = new Gen( delegate { ei.Compile(); ilg.Emit(OpCodes.Call, TextValue.toNakedCharMethod); localSuccess.Generate(ilg); }); } else if (argType == typeof(System.String)) { ifSuccess = new Gen( delegate { ei.Compile(); UnwrapToString(localSuccess, ifError); }); } else // General cases: String[], double[], double[,], ... { ifSuccess = new Gen( delegate { ei.Compile(); ilg.Emit(OpCodes.Call, ef.ArgConverter(argIndex).Method); if (argType.IsValueType) // must unbox wrapped value type, but this is too simple-minded { ilg.Emit(OpCodes.Unbox, argType); } localSuccess.Generate(ilg); }); } } ifSuccess.Generate(ilg); }
public CGGreaterThan(CGExpr[] es) : base(es, gtApplier) { }
public CGAnd(CGExpr[] es) : base(es) { }
public CGIf(CGExpr[] es) : base(es) { }
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 CGOr(CGExpr[] es) : base(es) { }
public override CGExpr Residualize(CGExpr[] res) { throw new ImpossibleException("CGSdfCall.Residualize"); }