// Return value of attribute with tuple indexing public TypedValue ValueNth(CodeValue attribute, NumberValue index, PointerValue lookup) { var row = lookup.Value as DataRow; Logger.Assert(row != null, "lookup is not row"); return(row.ValueOffset(attribute.AsEval, (int)index.Value, OffsetModes.Absolute)); }
// Return ordinal as scalar public NumberValue OrdinalGroup(PointerValue lookup) { var row = lookup.Value as DataRow; Logger.Assert(row != null, "lookup is not row"); return(row.Ordinal(true)); }
// Invoke a defined function with required argument in scope // If folded, applies an offset to get the right accumulator public TypedValue Invoke(CodeValue funcarg, PointerValue accblkarg, NumberValue accbasarg, TypedValue[] valargs) { Logger.WriteLine(3, "Invoke {0} accbase={1} ({2})", funcarg, accbasarg, String.Join(",", valargs.Select(a => a.ToString()).ToArray())); // wrap raw value with evaluator var expr = funcarg.Value as ExpressionEval; Logger.Assert(expr != null, "invoke eval"); var args = DataRow.CreateNonTuple(expr.Lookup, valargs); TypedValue ret; if (expr.HasFold) { var accblk = accblkarg.Value as AccumulatorBlock; var accbase = (int)accbasarg.Value; ret = expr.EvalHasFold(args, accblk, accbase); } else { ret = expr.EvalOpen(args); } // If the return value is an unresolved sql table then resolve it now // before exiting the lookup scope (which it may need) if (ret is RelationValue && !(ret.AsTable() is DataTableLocal)) { ret = RelationValue.Create(DataTableLocal.Convert(ret.AsTable(), args, expr.Evaluator)); } Logger.WriteLine(3, "[Inv {0}]", ret); return(ret); }
// Return rank of attribute with tuple indexing public TypedValue Rank(CodeValue attribute, NumberValue index, PointerValue lookup) { var row = lookup.Value as DataRow; Logger.Assert(row != null, "lookup is not row"); var value = attribute.AsEval.EvalOpen(row); var offset = row.Heading.FindIndex(attribute.AsEval.Name); return(NumberValue.Create(index.Value + 1)); }
// Fold an operation and one argument over a set of tuples public TypedValue Fold(PointerValue accblkarg, NumberValue accidarg, TypedValue defarg, CodeValue expr) { Logger.WriteLine(3, "Fold n={0} def={1} expr={2}", accidarg, defarg, expr); var accblock = accblkarg.Value as AccumulatorBlock; var accid = (int)accidarg.Value; var accum = accblock[accid] ?? defarg; accblock[accid] = expr.AsEval.EvalIsFolded(null, accblock[accid]); Logger.WriteLine(3, "[Fold {0}]", accblock[accid]); return(accblock[accid]); }
// Invoke a do block with its own scope level public TypedValue DoBlock(CodeValue exprarg, PointerValue accblkarg) { Logger.WriteLine(3, "DoBlock {0}", exprarg); _catvars = _catvars.PushScope(); var accblk = accblkarg.Value as AccumulatorBlock; var expr = exprarg.Value as ExpressionEval; var ret = expr.Evaluator.Exec(exprarg.Value.Code, null, null, accblk); // If the return value is an unresolved sql table then resolve it now // before exiting the local variable scope (which it may need) if (ret is RelationValue && !(ret.AsTable() is DataTableLocal)) { ret = RelationValue.Create(DataTableLocal.Convert(ret.AsTable())); } _catvars = _catvars.PopScope(); Logger.WriteLine(3, "[Do {0}]", ret); return(ret); }
public TypedValue Fold2(TypedValue defarg, CodeValue expr, PointerValue accblkarg, NumberValue accidarg) { return(null); }
static PointerValue() { Default = new PointerValue { Value = new byte[0] }; }
// Evaluation engine for ByteCode TypedValue Run(ByteCode bcode, TypedValue aggregate, AccumulatorBlock accblock) { TypedValue retval = null; var reader = PersistReader.Create(bcode.bytes); while (reader.More) { var opcode = reader.ReadOpcode(); switch (opcode) { // Known literal, do not translate into value case Opcodes.LDVALUE: PushStack(reader.ReadValue()); break; // Known catalog variable, look up value //case Opcodes.LDCAT: // var catnam = reader.ReadString(); // var catval = CatVars.GetValue(catnam); // Logger.Assert(catval != null, $"{opcode}:{catnam}"); // if (catval.DataType is DataTypeCode) // catval = this.Exec((catval as CodeValue).Value.Code); // _stack.Push(catval); // break; // Catalog variable, look up value (could be code) case Opcodes.LDCAT: var catnam = reader.ReadString(); var catval = CatVars.GetValue(catnam); Logger.Assert(catval != null, $"{opcode}:{catnam}"); _stack.Push(catval); break; // Catalog variable, must be code, evaluate case Opcodes.LDCATV: var ctvnam = reader.ReadString(); var ctvval = CatVars.GetValue(ctvnam) as CodeValue; Logger.Assert(ctvval != null, $"{opcode}:{ctvnam}"); _stack.Push(this.Exec((ctvval as CodeValue).Value.Code)); break; // Catalog variable, must be code, as code value case Opcodes.LDCATR: var ctrnam = reader.ReadString(); var ctrval = CatVars.GetValue(ctrnam) as CodeValue; Logger.Assert(ctrval != null, $"{opcode}:{ctrnam}"); PushStack(CodeValue.Create(ExpressionEval.Create(this, ctrval.Value))); break; // Load value obtained using lookup by name case Opcodes.LDFIELD: var fldval = TypedValue.Empty; var fldnam = reader.ReadString(); var fldok = LookupValue(fldnam, ref fldval); Logger.Assert(fldok, $"{opcode}:{fldnam}"); PushStack(fldval); break; // Load aggregate value or use specified start value if not available case Opcodes.LDAGG: var aggval = reader.ReadValue(); PushStack(aggregate ?? aggval); break; // load accumulator by index, or fixed value if not available case Opcodes.LDACC: var accnum = reader.ReadInteger(); var accval = reader.ReadValue(); PushStack(accblock == null ? accval : accblock[accnum]); break; // Load a segment of code for later call, with this evaluator packaged in case Opcodes.LDSEG: var segexp = reader.ReadExpr(); var segval = CodeValue.Create(ExpressionEval.Create(this, segexp)); PushStack(segval); break; case Opcodes.LDLOOKUP: var lkpobj = PointerValue.Create(_lookups.Peek() as object); PushStack(lkpobj); break; case Opcodes.LDACCBLK: var acbobj = PointerValue.Create(accblock as object); PushStack(acbobj); break; case Opcodes.LDCOMP: var cmpudt = _stack.Pop() as UserValue; var cmpval = cmpudt.GetComponentValue(reader.ReadString()); PushStack(cmpval); break; case Opcodes.LDFIELDT: var fdttup = _stack.Pop() as TupleValue; var fdtval = fdttup.GetFieldValue(reader.ReadString()); PushStack(fdtval); break; // Call a function, fixed or variable arg count case Opcodes.CALL: case Opcodes.CALLV: case Opcodes.CALLVT: var calname = reader.ReadString(); var calmeth = typeof(Builtin).GetMethod(calname); var calnargs = reader.ReadByte(); var calnvargs = reader.ReadByte(); var calargs = new object[calnargs]; var calargx = calargs.Length - 1; if (opcode == Opcodes.CALLV) { var vargs = new CodeValue[calnvargs]; for (var j = vargs.Length - 1; j >= 0; --j) { vargs[j] = _stack.Pop() as CodeValue; } calargs[calargx--] = vargs; } else if (opcode == Opcodes.CALLVT) { var vargs = new TypedValue[calnvargs]; for (var j = vargs.Length - 1; j >= 0; --j) { vargs[j] = _stack.Pop() as TypedValue; } calargs[calargx--] = vargs; } for (; calargx >= 0; --calargx) { calargs[calargx] = _stack.Pop(); } var ret = calmeth.Invoke(_builtin, calargs) as TypedValue; _stack.Push(ret); //if (ret.DataType != DataTypes.Void) // _stack.Push(ret); break; case Opcodes.EOS: retval = _stack.Pop(); //retval = (_stack.Count > 0) ? _stack.Pop() : VoidValue.Void; break; default: throw new NotImplementedException(opcode.ToString()); } } if (retval == null) { retval = _stack.Pop(); } //Logger.Assert(retval != null, "stack"); return(retval); }