/// <summary> /// Default implementation of <see cref="IAccessorVisitor.Visit"/> that supports evaluation of intrinsic /// functions Number(), String(), Boolean(). /// By overriding this any binding to to external objects can be achieved (recall to call this base /// method when overriding). /// </summary> /// <param name="frame">The current frame (gives access to the next frame if any).</param> public virtual PExpr Visit(IAccessorFrame frame) { IAccessorMemberFrame head = frame as IAccessorMemberFrame; // We can only handle member access at the root level: if (head == null) { return(frame.SetError()); } // Lookup from the longest path to the head in registered objects: // more "precise" objects mask root ones. var deepestMemberFrame = frame.NextAccessors(true) .Select(f => f as IAccessorMemberFrame) .TakeWhile(f => f != null) .LastOrDefault(); // We obtain at least the head, hence the do...while. do { RuntimeObj obj; if (_objects.TryGetValue(deepestMemberFrame.Expr.MemberFullName, out obj)) { return(deepestMemberFrame.SetResult(obj)); } deepestMemberFrame = deepestMemberFrame.PrevMemberAccessor; }while(deepestMemberFrame != null); var s = frame.GetImplementationState(c => c.On("Number").OnCall((f, args) => { if (args.Count == 0) { return(f.SetResult(DoubleObj.Zero)); } return(f.SetResult(args[0] as DoubleObj ?? DoubleObj.Create(args[0].ToDouble()))); } ) .On("String").OnCall((f, args) => { if (args.Count == 0) { return(f.SetResult(StringObj.EmptyString)); } return(f.SetResult(StringObj.Create(args[0].ToString()))); }) .On("Boolean").OnCall((f, args) => { return(f.SetResult(args.Count == 1 && args[0].ToBoolean() ? BooleanObj.True : BooleanObj.False)); }) ); return(s != null?s.Visit() : frame.SetError()); }