context: //#define TRACE_SCOPE
  //#define TEXT_FRAME_PERFORMANCE_TRACE
  //#define BINARY_FRAME_PERFORMANCE_TRACE
  //#define STRICT_OWNER_THREAD_VALIDATION
  #define APHID_FRAME_ADD_DATA
  #define APHID_FRAME_CATCH_POP
  #define TRACK_PREVIOUS_SCOPE
  
  using System;
  using System.Collections;
  using System.Collections.Generic;
  #if TRACE_SCOPE || TEXT_FRAME_PERFORMANCE_TRACE || BINARY_FRAME_PERFORMANCE_TRACE
  using System.Diagnostics;
  #endif
  using System.IO;
  using System.Linq;
  using System.Reflection;
  using System.Runtime;
  using System.Runtime.CompilerServices;
  using System.Text;
  using System.Threading;
  
  using Components.Aphid.Compiler;
  using Components.Aphid.Debugging;
  using Components.Aphid.Lexer;
  using Components.Aphid.Parser;
  using Components.Aphid.Parser.Fluent;
  using Components.Aphid.Serialization;
  using Components.Aphid.TypeSystem;
  using Components.Aphid.UI;
  #if TRACE_SCOPE || TEXT_FRAME_PERFORMANCE_TRACE || BINARY_FRAME_PERFORMANCE_TRACE
  using Components.External;
  #endif
  using Components.External.ConsolePlus;
  
  using static System.Convert;
  using static System.String;
  using static Components.Aphid.Lexer.AphidTokenType;
  using static Components.Aphid.TypeSystem.AphidObject;
  using static Components.Aphid.TypeSystem.TypeExtender;
  using static Components.Aphid.TypeSystem.ValueHelper;
  
  using Exp = Components.Aphid.Parser.AphidExpressionType;
  using LinqExp = System.Linq.Expressions.Expression;
  
  [assembly: InternalsVisibleTo("aphid-debug")]
  
  namespace Components.Aphid.Interpreter
  {
      // Todo:
      // * Fix all methods that return object instead of AphidObject,
      //   then remove excessive Wrap/Unwrap and casting.
      // * Add support for token macros--transform during lexical analysis
      //   instead of parsing.
      // * Text mutators as well, akin to C macros
      // * Add preprocessor looping support
      //   - Spin up secondary interpreter during preprocessing to easily
      //     support state, complex filter/projection, etc.
      // * Add quote support for macros.
      // * Add optional 'using' validation controlled via directive.
      //   - Cache previously loaded asm names at start, subscribe to
      //     AppDomain events to refresh cache.
      // * Add throw support.
      // * Add void ret support.
      // * Expand aphid function capabilities.
      //   - Add in default values e.g. f = @(x = 10, y = 'test') { /* ... */ }
      //   - Add in named params: f(y: 'test2');
      //   - Add tuple support e.g. 'test', x @Console.WriteLine('Foo: {0} {1}')
      //   - Add decomposition e.g. x, y = f();
      //     * Support decomposition of tuples and anything that implements IEnumerable
      //   - Add support for param/return type and constraint declarations.
      //     * Explicit return type: @(string value, int count : string) { ... }
      //     * Mixed type (no type for value): @(value, int count : string) { ... }
      //     * Implicit void return type: @(string msg) { ... }
      //     * Constraint (if null return null): @(value -> null, int count) { ... }
      //     * Multi Constraint (if x return x else if y return y etc):
      //          repeat = @(value -> null | '', int count) { ... }
      //     * Pattern Constraint:
      //          indexOf = @(value :== '' -> -1) { ... }
      //     * Mixed Constraint:
      //          indexOf = @(value -> null :== '' -> -1) { ... }
      //   - Add auto param attribute -- if argument is not explicitly passed, resolves
      //     by parameter name and passes value e.g.
      //     var foo = 'test'; var f = @(auto foo) foo @print('Message: {0}');
      // * Add lazy keyword.
      //   - Expression support: x = lazy f()
      //   - Param support: foo = @(lazy arg0) { ... }
      //   - Op param support:
      //      @ ?> = @(lazy lhs, lazy rhs) { ... }
      // * Implicit var support e.g.
      //   isTypeEnumerableOf = @(enumerableType, type)
      //       (var type.GetInterface('IEnumerable`1')) != null &&
      //       $&.GetGenericArguments()[0] == enumerableType;
      // * Support Aphid implemented operator override for types, via class decl and 
      //   extend
      // * Seamless implicit/explicit operator interop
      // * AphidShell script monitors build, kills and optionally restarts processes 
      //   that hold blocking file locks.
      // * Add update-safe loader that moves Aphid to a unique folder immediately
      //   following build/deploy and forward execution.
      //   - Forward via aphid.exe stub built using IL header
      //     * Add inline assembly support (stretch)
      //   - Use CrossProcessLock to sync bootstrap execution/overwrite.
      // * Add yield return/break support, possibly infer based on lazy attribute
      // * Add contextual semantics for | --binary OR for numbers, pipe for callables.
      // * Create standalone debugger.
      //   - Build both command-line and graphical interfaces.
      //   - Add ability to open Aphid-specific crash dumps.
      //   - Add execution rewind.
      //   - Add replay of trace dumps.
      //   - Support editing of code in memory.
      //   - Act as JIT debugger when Aphid scripts crash.
      // * Add execution tracing with multiple levels.
      //   - Levels by granularity, descending: script, func, block, stmt, and expr.
      // * Create object database system (AphidDB).
      //   - Compile high performance serializers (must support several TB databases).
      //   - Persist Aphid bytecode and metadata for use as indexes.
      //   - Pull pieces from AphidUI for use as generic database management UI.
      //   - Memoize query bytecode and results for hot paths.
      // * Add enum support.
      // * Add struct support.
      //   - Support first-class unions with FieldOffsetAttribute.
      //   - Add first-class pointer support.
      // * Generate new bitwise operator implementations based on
      //   public AphidObject BinaryAnd(AphidObject x, AphidObject y)
      // * Look into generating interpreter thunks that handle interpreter
      //   construction and forwarding when public interpret methods are called
      //   from non-owner threads.
      // * Add using keyword support for IDisposable.
      // * Add scope keyword support for automatic disposal immediately upon leaving
      //   leaving scope via ascend (not descend) or by breaking scope chain entirely.
      // * Consider pure console IDE.
      //   -Draw inspiration from edit.com
      // * Add fan-out support for C# generation e.g.
      //   AphidCli.*()->AphidCli.Try*()
      //   AphidCli.*()->$_.Try*
      // * Support [] attributes by matching identifier after array decl/access
      //   to support multiple attrs declared with any expression
      // * Add jmp/goto support
      // * Replace foreach, Select, etc. with for.
      [Serializable]
      public partial class AphidInterpreter
      {
          #region Constants
  
          private const bool _createLoaderDefault = true;
  
  #if EXPRESSION_HISTORY
          internal const int ExpressionHistorySize = 0x100;
  #endif
  
          #endregion
  
          #region Static Readonly Fields
          //[ThreadStatic]        
  
          private static readonly Dictionary<Type, Dictionary<string, MemberInfo[]>>
              _instanceMemberNameCache = new(),
              _staticMemberNameCache = new();
  
          private static readonly FieldInfo _frameArray = typeof(Stack<AphidFrame>)
              .GetField("_array", BindingFlags.Instance | BindingFlags.NonPublic);
  
          #endregion
  
          #region Instance Readonly Fields
  
          private readonly Lazy<Func<AphidFrame[]>> _lazyGetFrameArray;
  
          private readonly Stack<AphidFrame> _frames;
  
          private readonly ReaderWriterLockSlim _importsLock = new();
  
          #endregion
  
          #region Instance Fields
  
          private bool _isReturning, _isContinuing, _isBreaking, _isInTryCatchFinally;
  
          private int _queuedFramePops;
  
          private IEnumerable<AphidExpression> _insertNextBuffer;
  
  #if APHID_DEBUGGING_ENABLED
          private List<AphidExpression> _currentBlock;
  
          private ManualResetEvent _breakpointReset;
  
          private bool _isSingleStepping;
  
          private AutoResetEvent _singleStepReset;
  
  #if EXPRESSION_HISTORY
          private ExpressionHistoryRecord[] _expressionHistory = new ExpressionHistoryRecord[ExpressionHistorySize];
  
          private int _expressionHistoryIndex = -1, _expressionHistoryCount = 0;
  
          private bool _isSteppingBack;
  #endif
  #endif
  
  #if TRACE_SCOPE
          private AphidTrace _scopeTrace;
  #endif
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
          private AphidTrace _framePerformanceTrace;
  
          private Stack<Tuple<string, Stopwatch>> _frameStopwatchStack = new Stack<Tuple<string, Stopwatch>>();
  #endif
  
  #if BINARY_FRAME_PERFORMANCE_TRACE
          private FrameProfileBinaryWriter _framePerformanceBinaryWriter;
  #endif
  
          private AphidObject _localScope, _currentScope;
  
  #if TRACK_PREVIOUS_SCOPE
          private AphidObject _previousScope;
  #endif
  
          #endregion
  
          #region Instance Properties
  
          public AphidObject InitialScope { get; private set; }
  
          public AphidObject CurrentScope
          {
              get => _currentScope;
              private set
              {
  #if TRACE_SCOPE
                  if (_scopeTrace != null)
                  {
                      _scopeTrace.Trace("Set scope begin");
                  }
  #endif
  #if TRACK_PREVIOUS_SCOPE
                  _previousScope = CurrentScope;
  #endif
  
  #pragma warning disable IDE0027 // Use expression body for accessors
                  _currentScope = value;
  #pragma warning restore IDE0027 // Use expression body for accessors
  #if TRACE_SCOPE
                  if (_scopeTrace != null)
                  {
                      _scopeTrace.Trace("Set scope end");
                  }
  #endif
              }
          }
  
  #if TRACK_PREVIOUS_SCOPE
          public AphidObject PreviousScope => _previousScope;
  #endif
  
  #if APHID_DEBUGGING_ENABLED
          public Dictionary<string, int[]> FileBreakpointIndexMap { get; private set; }
  
          public string CurrentFileContext { get; private set; }
  
          public Action<AphidExpression> HandleExecutionBreak { get; set; }
  
  #if EXPRESSION_HISTORY
          internal ExpressionHistoryRecord[] ExpressionHistory => _expressionHistory;
  
          internal int ExpressionHistoryIndex => _expressionHistoryIndex;
  
          internal int ExpressionHistoryCount => _expressionHistoryCount;
  #endif
  #endif
  
          public int OwnerThread { get; private set; }
  
          public AphidAssemblyBuilder AsmBuilder { get; }
  
          public InteropMethodResolver InteropMethodResolver { get; }
  
          public OperatorHelper OperatorHelper { get; }
  
          public ValueHelper ValueHelper { get; }
  
          public InteropTypeResolver InteropTypeResolver { get; }
  
          public TypeExtender TypeExtender { get; }
  
          public AphidTypeConverter TypeConverter { get; }
  
          public AphidFunctionConverter FunctionConverter { get; }
  
          public AphidIpcContext IpcContext { get; private set; }
  
          public AphidSerializer Serializer { get; set; }
  
          public TextWriter Out { get; set; }
  
          public Func<string, string> OutFilter { get; set; }
  
          public Func<string, string> GatorEmitFilter { get; set; }
  
          public AphidLoader Loader { get; private set; }
  
          public AphidExpression CurrentStatement { get; private set; }
  
          public AphidExpression CurrentExpression { get; private set; }
  
          public bool StrictMode { get; set; }
  
          public Func<AphidFrame[]> GetFrameArray => _lazyGetFrameArray.Value;
  
          #endregion
  
          #region Constructors
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidInterpreter()
              : this(Scope(), createLoader: _createLoaderDefault, loader: null, frames: null)
          {
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidInterpreter(bool createLoader)
              : this(Scope(), createLoader, loader: null, frames: null)
          {
              // Optimize by generating all built-in
              // variables here without having to perform
              // key existence checks.
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidInterpreter(AphidObject currentScope)
              : this(currentScope, createLoader: _createLoaderDefault, loader: null, frames: null)
          {
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidInterpreter(AphidObject currentScope, bool createLoader)
              : this(currentScope, createLoader, loader: null, frames: null)
          {
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidInterpreter(AphidLoader loader)
              : this(Scope(), createLoader: false, loader: loader, null)
          {
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidInterpreter(AphidObject currentScope, AphidLoader loader)
              : this(currentScope, createLoader: false, loader: loader, frames: null)
          {
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidInterpreter(AphidObject currentScope, Stack<AphidFrame> frames)
              : this(currentScope, createLoader: _createLoaderDefault, loader: null, frames: frames)
          {
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidInterpreter(AphidObject currentScope, bool createLoader, Stack<AphidFrame> frames)
              : this(currentScope, createLoader: createLoader, loader: null, frames: frames)
          {
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidInterpreter(
              AphidObject currentScope,
              bool createLoader,
              AphidLoader loader,
              Stack<AphidFrame> frames)
          {
              AphidErrorReporter.Init();
              StrictMode = AphidConfig.Current.StrictMode;
  
              Loader = createLoader ? new AphidLoader(this) : loader;
  
              InitialScope = CurrentScope = currentScope ?? Scope();
  
              OwnerThread = -1;
  #if TRACE_SCOPE
              _scopeTrace = new AphidTrace(
                  "Scope Trace",
                  PathHelper.GetExecutingPath(
                      Format("AphidScope.{0}.log", Guid.NewGuid())),
                  this)
                  {
                      Settings = new AphidTraceSettings
                      {
                          TraceTimestamp = true,
                          DefaultMessageTraceLevel = TraceLevel.Info,
                          TimestampFormat = AphidTraceSettings.DefaultTimestampFormat,
                          TraceAphidStack = false,
                          TraceCurrentExpression = false,
                          TraceCurrentStatement = false,
                          TraceClrStack = true,
                      },
                  };
  
              _scopeTrace.Open();
  #endif
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
              var framePerfGuid = Guid.NewGuid();
  
              var frameStart = Format(
                  "Tracing frame performance beginning at:\r\n{0}\r\n\r\n",
                  new StackTrace().ToString());
  #endif
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
              _framePerformanceTrace = new AphidTrace(
                  "Frame performance Trace",
                  PathHelper.GetExecutingPath(
                      Format("AphidFramePerformance.{0}.log", framePerfGuid)),
                  this)
                   {
                      Settings = new AphidTraceSettings
                      {
                          TraceTimestamp = false,
                          DefaultMessageTraceLevel = TraceLevel.Info,
                          TimestampFormat = AphidTraceSettings.DefaultTimestampFormat,
                          TraceAphidStack = false,
                          TraceCurrentExpression = false,
                          TraceCurrentStatement = false,
                          TraceClrStack = false,
                      },
                  };
  
              _framePerformanceTrace.Open();
              _framePerformanceTrace.TraceText(frameStart);
              _framePerformanceTrace.Flush();
  #endif
  
  #if BINARY_FRAME_PERFORMANCE_TRACE
              if (frames == null)
              {
                  _framePerformanceBinaryWriter = new FrameProfileBinaryWriter(Guid.NewGuid());
                  _framePerformanceBinaryWriter.WriteStart();
              }
  #endif
  
  #if APHID_DEBUGGING_ENABLED
              FileBreakpointIndexMap = new Dictionary<string, int[]>(
                  StringComparer.OrdinalIgnoreCase);
  #endif
  
              Out = Console.Out;
              AsmBuilder = new AphidAssemblyBuilder(this, _importsLock);
  
              InteropMethodResolver = new InteropMethodResolver(
                  this,
                  InterpretMemberInteropExpression,
                  _importsLock);
  
              OperatorHelper = new OperatorHelper(this);
              ValueHelper = new ValueHelper(this);
              TypeExtender = new TypeExtender(this, _importsLock);
              InteropTypeResolver = new InteropTypeResolver(this);
              TypeConverter = new AphidTypeConverter(this);
              FunctionConverter = new AphidFunctionConverter(this);
  
              Serializer = new AphidSerializer(this)
              {
                  IgnoreSpecialVariables = false,
                  IgnoreFunctions = true,
                  QuoteToStringResults = true
              };
  
              _frames = frames ?? new Stack<AphidFrame>(new[] { CreateEntryFrame() });
  
              _lazyGetFrameArray = new Lazy<Func<AphidFrame[]>>(() =>
                  LinqExp
                      .Lambda<Func<AphidFrame[]>>(
                          LinqExp.Field(LinqExp.Constant(_frames, typeof(Stack<AphidFrame>)), _frameArray))
                      .Compile());
  
              if (!CurrentScope.ContainsKey(AphidName.Scope))
              {
                  CurrentScope.Add(AphidName.Scope, CurrentScope);
              }
  
              if (!CurrentScope.ContainsKey(AphidName.Parent))
              {
                  CurrentScope.Add(AphidName.Parent, CurrentScope.Parent);
              }
  
              if (!CurrentScope.ContainsKey(AphidName.FramesKey))
              {
                  CurrentScope.Add(AphidName.FramesKey, Scalar(_frames));
              }
  
              if (!CurrentScope.ContainsKey(AphidName.AsmBuilder))
              {
                  CurrentScope.Add(AphidName.AsmBuilder, Scalar(AsmBuilder));
              }
  
              if (!CurrentScope.ContainsKey(AphidName.Interpreter))
              {
                  CurrentScope.Add(AphidName.Interpreter, Scalar(this));
              }
  
              InitialScope = CurrentScope;
          }
  
          #endregion
  
          #region Interpreter State Methods
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public HashSet<string> GetImports()
          {
              if (CurrentScope.TryResolve(AphidName.Imports, out var imports))
              {
                  return (HashSet<string>)imports.Value;
              }
  
              var list = new HashSet<string>(AphidConfig.Current.Imports);
              CurrentScope.Add(AphidName.Imports, Scalar(list));
  
              return list;
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void AddImport(string name)
          {
              _importsLock.EnterWriteLock();
  
              try
              {
                  var imports = GetImports();
  
                  if (!imports.Contains(name))
                  {
                      imports.Add(name);
                  }
              }
              finally
              {
                  _importsLock.ExitWriteLock();
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidObject GetReturnValue() => GetReturnValue(false);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidObject GetReturnValue(bool remove)
          {
              if (CurrentScope.TryGetValue(AphidName.Return, out var retVal) && remove)
              {
                  CurrentScope.Remove(AphidName.Return);
              }
  
              return retVal;
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private void SetReturnValue(AphidObject obj) => CurrentScope.Add(AphidName.Return, obj);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void SetScriptFilename(string filename)
          {
              var obj = Scalar(filename);
  
              if (!CurrentScope.ContainsKey(AphidName.Script))
              {
                  CurrentScope.Add(AphidName.Script, obj);
              }
              else
              {
                  CurrentScope.Remove(AphidName.Script);
                  CurrentScope.Add(AphidName.Script, obj);
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public string GetScriptFilename() => CurrentScope != null
                  ? CurrentScope.TryResolve(AphidName.Script, out var scriptObj) ?
                      scriptObj?.GetString() :
                      null
                  : null;
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public bool SetIsInTryCatchFinally(bool value)
          {
              var old = _isInTryCatchFinally;
              _isInTryCatchFinally = value;
  
              return old;
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void ResetState()
          {
              CurrentScope = InitialScope;
  
              // Todo: Add test cases to cover try/catch influence
              CurrentExpression = null;
              CurrentStatement = null;
              _isReturning = false;
              _isContinuing = false;
              _isBreaking = false;
              _isInTryCatchFinally = false;
              _frames.Clear();
              _frames.Push(CreateEntryFrame());
              _queuedFramePops = 0;
  
              if (CurrentScope.ContainsKey(AphidName.Return))
              {
                  CurrentScope.Remove(AphidName.Return);
              }
  
              //if (CurrentScope.ContainsKey(AphidName.Block))
              //{
              //    CurrentScope.Remove(AphidName.Block);
              //}
  
              //if (CurrentScope.ContainsKey(AphidName.Script))
              //{
              //    CurrentScope.Remove(AphidName.Script);
              //}
  
  #if APHID_SET_CODE_VAR
              if (CurrentScope.ContainsKey(AphidName.Code))
              {
                  CurrentScope.Remove(AphidName.Code);
              }
  #endif
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void InsertNext(IEnumerable<AphidExpression> block)
          {
              if (_insertNextBuffer != null)
              {
                  CreateRuntimeException("Cannot insert block, buffer already set.");
              }
  
              _insertNextBuffer = block;
          }
  
  #if APHID_SET_CODE_VAR
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private void SetAstCode(List<AphidExpression> ast)
          {
              if (CurrentScope.ContainsKey(AphidName.Code))
              {
                  CurrentScope.Remove(AphidName.Code);
              }
  
              var node = ast.FirstOrDefault(x => x.Code != null);
              CurrentScope.Add(AphidName.Code, Scalar(node != null ? node.Code : null));
          }
  #endif
  
          #endregion
  
          #region Scope Methods
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void SetInitialScope(AphidObject scope) =>
              CurrentScope = InitialScope = scope;
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void EnterScope()
          {
  #if TRACE_SCOPE
              _scopeTrace.Trace("Enter scope begin");
  #endif
  
              CurrentScope = Scope(CurrentScope);
              CurrentScope.Add(AphidName.Scope, CurrentScope);
              CurrentScope.Add(AphidName.Parent, CurrentScope.Parent);
  
  #if TRACE_SCOPE
              _scopeTrace.Trace("Enter scope end");
  #endif
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public bool LeaveScope(bool bubbleReturnValue = false)
          {
  #if TRACE_SCOPE
              _scopeTrace.Trace("Leave scope begin");
  #endif
  
              if (CurrentScope.Parent == null)
              {
  #if TRACE_SCOPE
                  _scopeTrace.Trace("Internal error leaving scope, parent scope is null.");
  #endif
  
                  throw CreateInternalException(
                      "Internal error leaving scope, parent scope is null.");
              }
  
              if (bubbleReturnValue)
              {
                  var ret = GetReturnValue(true);
                  CurrentScope = CurrentScope.Parent;
  
                  if (ret != null)
                  {
                      SetReturnValue(ret);
  
  #if TRACE_SCOPE
                      _scopeTrace.Trace("Leave scope end");
  #endif
  
                      return true;
                  }
              }
              else
              {
                  CurrentScope = CurrentScope.Parent;
              }
  
  #if TRACE_SCOPE
              _scopeTrace.Trace("Leave scope end");
  #endif
  
              return false;
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void EnterSharedScope(AphidObject sharedScope) =>
              EnterSharedScope(sharedScope, createChild: true);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void EnterSharedScope(AphidObject sharedScope, bool createChild)
          {
              if (_localScope != null)
              {
                  throw CreateRuntimeException(
                      "Already in shared scope, cannot enter another.");
              }
  
              _localScope = CurrentScope;
  
              CurrentScope = !createChild ?
                  sharedScope :
                  Scope(sharedScope);
  
              PushFrame("[Shared Scope]");
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void LeaveSharedScope()
          {
              PopFrame();
  
              if (_localScope == null)
              {
                  throw CreateRuntimeException(
                      "Leave shared scope failed, not in shared scope.");
              }
  
              CurrentScope = _localScope;
              _localScope = null;
          }
  
          #endregion
  
          #region IO Methods
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void WriteOut(string text)
          {
              if (Out != null)
              {
                  if (OutFilter != null)
                  {
                      text = OutFilter(text);
                  }
  
                  Out.Write(text);
              }
          }
  
          #endregion
  
          #region CLR Interop Methods
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private MemberInfo[] GetInteropInstanceMembers(object target, BinaryOperatorExpression expression) =>
              GetTypeInteropInstanceMembers(target.GetType(), GetMemberKey(expression.RightOperand));
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private static MemberInfo[] GetInteropInstanceMembers(object target, string name) =>
              GetTypeInteropInstanceMembers(target.GetType(), name);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private static MemberInfo[] GetTypeInteropInstanceMembers(Type targetType, string name)
          {
              lock (_instanceMemberNameCache)
              {
                  MemberInfo[] members;
                  if (!_instanceMemberNameCache.TryGetValue(targetType, out var nameMembers))
                  {
                      members = GetTypeInteropInstanceMembersCore(targetType, name);
  
                      _instanceMemberNameCache.Add(
                          targetType,
                          new Dictionary<string, MemberInfo[]> { { name, members } });
                  }
                  else if (!nameMembers.TryGetValue(name, out members))
                  {
                      members = GetTypeInteropInstanceMembersCore(targetType, name);
                      nameMembers.Add(name, members);
                  }
  
                  return members;
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private static MemberInfo[] GetTypeInteropInstanceMembersCore(Type targetType, string name)
          {
              var allMembers = targetType.GetMembers(
                  BindingFlags.FlattenHierarchy |
                  BindingFlags.Public |
                  BindingFlags.Instance |
                  BindingFlags.Static);
  
              var members = new MemberInfo[allMembers.Length];
              var count = 0;
  
              for (var i = 0; i < allMembers.Length; i++)
              {
                  var am = allMembers[i];
  
                  if (am.Name == name)
                  {
                      members[count++] = am;
                  }
              }
  
              if (count != members.Length)
              {
                  Array.Resize(ref members, count);
              }
  
              return members;
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private static MemberInfo[] GetInteropStaticMembers(Type type, string[] path) =>
              GetInteropStaticMembers(type, path[path.Length - 1]);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private static MemberInfo[] GetInteropStaticMembers(Type targetType, string name)
          {
              lock (_staticMemberNameCache)
              {
                  MemberInfo[] members;
                  if (!_staticMemberNameCache.TryGetValue(targetType, out var nameMembers))
                  {
                      members = GetInteropStaticMembersCore(targetType, name);
  
                      _staticMemberNameCache.Add(
                          targetType,
                          new Dictionary<string, MemberInfo[]> { { name, members } });
                  }
                  else if (!nameMembers.TryGetValue(name, out members))
                  {
                      members = GetInteropStaticMembersCore(targetType, name);
                      nameMembers.Add(name, members);
                  }
  
                  return members;
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private static MemberInfo[] GetInteropStaticMembersCore(Type targetType, string name)
          {
              var allMembers = targetType.GetMembers(
                  BindingFlags.Static |
                  BindingFlags.Public |
                  BindingFlags.FlattenHierarchy);
  
              var members = new MemberInfo[allMembers.Length];
              var count = 0;
  
              for (var i = 0; i < allMembers.Length; i++)
              {
                  var am = allMembers[i];
  
                  if (am.Name == name)
                  {
                      members[count++] = am;
                  }
              }
  
              if (count != members.Length)
              {
                  Array.Resize(ref members, count);
              }
  
              return members;
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private bool HandleInteropReference(AphidInteropReference interopRef, AphidObject value)
          {
              if (interopRef == null)
              {
                  return false;
              }
  
              var v = value.Value;
  
              if (interopRef.Field != null)
              {
                  interopRef.Field.SetValue(
                      interopRef.Object,
                      TypeConverter.Convert(interopRef.Field.FieldType, v, null));
              }
              else
              {
                  interopRef.Property.SetValue(
                      interopRef.Object,
                      v != null ?
                          TypeConverter.Convert(interopRef.Property.PropertyType, v, null) :
                          null);
              }
  
              if (Unwrap(value) is AphidFunction func)
              {
                  func.ParentScope = interopRef.Object is AphidObject ao ? ao : CurrentScope;
              }
  
              return true;
          }
  
          #endregion
  
          #region Function Call Methods
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidObject CallFunction(string name, params object[] parms)
          {
              var idExp = new IdentifierExpression(name);
              PushFrame(idExp, name, parms);
  
              try
              {
                  return CallFunction(InterpretIdentifierExpression(idExp), parms);
              }
  #if APHID_FRAME_ADD_DATA || APHID_FRAME_CATCH_POP
  #if APHID_FRAME_ADD_DATA
              catch (Exception e)
  #else
              catch
  #endif
              {
                  if (e.Source != AphidName.DebugInterpreter)
                  {
                      e.Source = AphidName.DebugInterpreter;
  #if APHID_FRAME_CATCH_POP
                      while (_queuedFramePops > 0)
                      {
                          _frames.Pop();
                          _queuedFramePops--;
                      }
  #endif
  
  #if APHID_FRAME_ADD_DATA
                      e.Data.Add(AphidName.Interpreter, this);
                      e.Data.Add(AphidName.FramesKey, GetRawStackTrace());
  #if TRACK_PREVIOUS_SCOPE
                      e.Data.Add(AphidName.Scope, PreviousScope);
  #endif
  #endif
                  }
  
                  throw;
              }
  #endif
              finally
              {
                  PopFrame();
              }
          }
  
          //Todo: add variations that eliminate params usage by having hardcoded arg counts.
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidObject CallFunction(AphidFunction function, params object[] parms) =>
              CallFunctionWithScope(function, null, parms);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidObject CallFunctionWithScope(AphidFunction function, AphidObject scope, params object[] parms)
          {
              var parmsWrapped = new AphidObject[parms.Length];
  
              for (var i = 0; i < parms.Length; i++)
              {
                  parmsWrapped[i] = Wrap(parms[i]);
              }
  
              //var parmsWrapped = parms.Select(Wrap).ToArray();
  
              //PushFrame(CurrentExpression, CurrentExpression, parms);
  
              //try
              //{
              if (Thread.CurrentThread.ManagedThreadId == OwnerThread)
              {
                  return CallFunctionCore(function, scope, parmsWrapped);
              }
  
              if (AphidErrorReporter.IsEnabled)
              {
                  try
                  {
                      return AphidThread.CreateChild(this).CallFunctionCore(function, scope, parmsWrapped);
                  }
                  catch (Exception e)
                  {
                      AphidErrorReporter.Report(e, passThrough: true);
  
                      return null;
                  }
              }
              else
              {
                  return AphidThread.CreateChild(this).CallFunctionCore(function, scope, parmsWrapped);
                  //Todo: proper error handling
                  //if (AphidErrorHandling.HandleErrors)
                  //{
                  //    try
                  //    {
                  //        return AphidThread.CreateChild(this).CallFunctionCore(function, scope, parmsWrapped);
                  //    }
                  //    catch (Exception e)
                  //    {
                  //        AphidCli.DumpException(
                  //    }
                  //}
              }
  
              //}
              //finally
              //{
              //    PopFrame();
              //}
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidObject CallFunctionCore(AphidFunction function, AphidObject[] parms) =>
              CallFunctionCore(function, null, parms);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidObject CallFunctionCore(AphidFunction function, AphidObject scope, AphidObject[] parms)
          {
              bool isExtension, isStaticExtension;
              AphidObject extensionArg;
              var functionScope = Scope(function.ParentScope);
              functionScope.Add(AphidName.Interpreter, Scalar(this));
  
              if (function.ParentScope != null)
              {
                  functionScope.Add(AphidName.Parent, function.ParentScope);
                  functionScope.Add(AphidName.Scope, functionScope);
  
                  if (function.ParentScope.TryGetValue(AphidName.Extension, out var isExtensionObject) &&
                      (bool)isExtensionObject.Value)
                  {
                      isExtension = true;
                      isStaticExtension = function.ParentScope.ResolveBool(AphidName.StaticExtension);
                      function.ParentScope.TryGetValue(AphidName.ImplicitArg, out extensionArg);
                  }
                  else
                  {
                      isExtension = isStaticExtension = false;
                      extensionArg = null;
                  }
              }
              else
              {
                  isExtension = isStaticExtension = false;
                  extensionArg = null;
              }
  
              for (var i = 0; i < parms.Length; i++)
              {
                  var arg = parms[i];
  
                  if (i == 0 && (!isExtension || isStaticExtension))
                  {
                      SetImplicitArg(functionScope, arg);
                  }
  
                  if (function.Args.Length == i)
                  {
                      break;
                  }
  
                  functionScope.Add(function.Args[i], arg);
              }
  
              var argList = parms.ToList();
  
              if (isExtension && !isStaticExtension)
              {
                  argList.Insert(0, extensionArg);
                  functionScope[AphidName.ImplicitArg] = extensionArg;
              }
  
              functionScope[AphidName.ImplicitArgs] = Scalar(argList);
  
              if (scope != null)
              {
                  functionScope.CopyTo(scope);
                  scope.Parent = functionScope.Parent;
                  functionScope = scope;
              }
  
              var parent = CurrentScope;
              CurrentScope = functionScope;
  
              try
              {
                  Interpret(function.Body);
  
                  return GetReturnValue(true);
              }
              finally
              {
                  CurrentScope = parent;
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private void SetImplicitArg(AphidObject arg) => SetImplicitArg(CurrentScope, arg);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private static void SetImplicitArg(AphidObject scope, AphidObject arg) =>
              scope[AphidName.ImplicitArg] = arg;
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidObject CallInteropFunction(AphidInteropFunction func, params AphidObject[] objArgs)
          {
              object[] args = objArgs;
  
              if (func.UnwrapParameters)
              {
                  for (var i = 0; i < objArgs.Length; i++)
                  {
                      args[i] = objArgs[i].Value;
                  }
              }
  
              return Wrap(func.Invoke(this, args));
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidObject CallFunction(AphidObject function, params object[] args)
          {
              return function.Value switch
              {
                  AphidFunction func => CallFunction(func, args),
                  AphidInteropFunction func2 => CallInteropFunction(func2, (AphidObject[])args),
                  _ => throw CreateRuntimeException("Object is not function: {0}", function),
              };
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidObject CallInteropFunction(
              AphidExpression callExpression,
              AphidInteropMethodInfo methodInfo,
              AphidInteropMember interopMembers)
          {
              MethodBase method = !methodInfo.Method.IsGenericMethod
                  ? methodInfo.Method
                  : ((MethodInfo)methodInfo.Method).MakeGenericMethod(methodInfo.GenericArguments);
              var convertedArgs = TypeConverter.Convert(
                  methodInfo.Arguments,
                  methodInfo.GenericArguments);
  
              PushFrame(
                  callExpression,
                  new Lazy<string>(() =>
                      Format(
                          "{0}.{1}",
                          AphidType.TypeToString(method.DeclaringType),
                          method.Name)),
                  convertedArgs);
  
              try
              {
                  return Wrap(
                      method.Invoke(
                          interopMembers.Target,
                          convertedArgs));
              }
  #if APHID_FRAME_ADD_DATA || APHID_FRAME_CATCH_POP
  #if APHID_FRAME_ADD_DATA
              catch (Exception e)
  #else
             catch
  #endif
              {
                  if (e.Source != AphidName.DebugInterpreter)
                  {
                      e.Source = AphidName.DebugInterpreter;
  #if APHID_FRAME_CATCH_POP
                      while (_queuedFramePops > 0)
                      {
                          _frames.Pop();
                          _queuedFramePops--;
                      }
  #endif
  
  #if APHID_FRAME_ADD_DATA
                      e.Data.Add(AphidName.Interpreter, this);
                      e.Data.Add(AphidName.FramesKey, GetRawStackTrace());
  #if TRACK_PREVIOUS_SCOPE
                      e.Data.Add(AphidName.Scope, PreviousScope);
  #endif
  #endif
                  }
  
                  throw;
              }
  #endif
              finally
              {
                  PopFrame();
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidObject CallStaticInteropFunction(CallExpression callExpression)
          {
              var path = FlattenPath(callExpression.FunctionExpression);
              var type = InteropTypeResolver.ResolveType(GetImports(), _importsLock, path);
              var methodName = path.Last();
  
              var args = new object[callExpression.Args.Count];
  
              for (var i = 0; i < args.Length; i++)
              {
                  args[i] = InterpretExpression(callExpression.Args[i]).Value;
              }
  
              var methodInfo = InteropMethodResolver.Resolve(type, methodName, args);
              MethodBase method;
  
              if (methodInfo.GenericArguments.Length == 0)
              {
                  method = methodInfo.Method;
              }
              else
              {
                  var m = (MethodInfo)methodInfo.Method;
                  Type[] generics;
  
                  if (methodInfo.GenericArguments.Length != (generics = m.GetGenericArguments()).Length)
                  {
                      throw CreateRuntimeException(
                          "Generic type parameter mismatch between {0} and {1}.",
                          methodInfo.Method.ToString(),
                          m.ToString());
                  }
  
                  method = m.MakeGenericMethod(generics);
              }
  
              return Wrap(
                  method.Invoke(null,
                      TypeConverter.Convert(
                          methodInfo.Arguments,
                          methodInfo.GenericArguments)));
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private string GetInteropAttribute(AphidExpression expression)
          {
              switch (expression.Type)
              {
                  case Exp.IdentifierExpression:
                      var attrs = ((IdentifierExpression)expression).Attributes;
  
                      if (attrs.Count == 1)
                      {
                          return attrs[0].Identifier;
                      }
  
                      return null;
  
                  case Exp.BinaryOperatorExpression:
                      return GetInteropAttribute(((BinaryOperatorExpression)expression).LeftOperand);
  
                  case Exp.CallExpression:
                      return GetInteropAttribute(((CallExpression)expression).FunctionExpression);
  
                  default:
                      return null;
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private static AphidObject CreateUnsafeArgument(AphidExpression argExp)
          {
              var arg = Complex();
              arg.Add("UnsafeArgument", Wrap(argExp));
  
              return arg;
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private object[] CreateSafeArgs(List<AphidExpression> argExpressions)
          {
              var args = new object[argExpressions.Count];
  
              for (var i = 0; i < argExpressions.Count; i++)
              {
                  try
                  {
                      args[i] = argExpressions[i] switch
                      {
                          IdentifierExpression exp => InterpretIdentifierExpression(exp),
                          BinaryOperatorExpression exp => InterpretMemberExpression(exp, false),
                          NumberExpression exp => InterpretNumberExpression(exp),
                          StringExpression exp => InterpretStringExpression(exp),
                          _ => argExpressions[i],//args[i] = CreateUnsafeArgument(argExpressions[i]);
                      };
                  }
                  catch (Exception e)
                  {
                      var a = CreateUnsafeArgument(argExpressions[i]);
                      a.Add("ArgumentException", Scalar(e));
                      args[i] = a;
                  }
              }
  
              return args;
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidObject CallCustomOperatorFunction(
              AphidExpression customOperatorExpression,
              AphidTokenType op,
              string name,
              object[] args)
          {
              var funcName = GetCustomOperatorFunction(op, name);
              var funcExp = CurrentScope.Resolve(this, GetCustomOperatorExpressionKey(op));
              PushFrame(customOperatorExpression, (AphidExpression)funcExp.Value, args);
  
              try
              {
                  return CallFunction(funcName, args);
              }
  #if APHID_FRAME_ADD_DATA || APHID_FRAME_CATCH_POP
  #if APHID_FRAME_ADD_DATA
              catch (Exception e)
  #else
              catch
  #endif
              {
                  if (e.Source != AphidName.DebugInterpreter)
                  {
                      e.Source = AphidName.DebugInterpreter;
  #if APHID_FRAME_CATCH_POP
                      while (_queuedFramePops > 0)
                      {
                          _frames.Pop();
                          _queuedFramePops--;
                      }
  #endif
  
  #if APHID_FRAME_ADD_DATA
                      e.Data.Add(AphidName.Interpreter, this);
                      e.Data.Add(AphidName.FramesKey, GetRawStackTrace());
  #if TRACK_PREVIOUS_SCOPE
                      e.Data.Add(AphidName.Scope, PreviousScope);
  #endif
  #endif
                  }
  
                  throw;
              }
  #endif
              finally
              {
                  PopFrame();
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidFunction GetCustomOperatorFunction(AphidTokenType op, string name)
          {
              if (!CurrentScope.TryResolve(GetCustomOperatorKey(op), out var obj))
              {
                  throw CreateRuntimeException("Custom operator '{0}' not defined.", op);
              }
  
              var func = obj.GetFunction();
  
              return func ?? throw CreateRuntimeException(
                      "Custom operator '{0}' should be function, was '{1}'.",
                      op,
                      obj.GetValueType());
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private static string GetCustomOperatorKey(AphidTokenType op) =>
              $"$customOperator.{op.ToString()}.body";
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private static string GetCustomOperatorExpressionKey(AphidTokenType op) =>
              $"$customOperator.{op.ToString()}.expression";
  
          #endregion
  
          #region Frame Management Methods
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void PushFrame(string name) => PushFrame(CreateNameFrame(name));
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void PushFrame(
              AphidExpression callExpression,
              AphidExpression functionExpression,
              IEnumerable<object> args)
          {
              var name = new Lazy<string>(() =>
              {
                  switch (functionExpression.Type)
                  {
                      case Exp.IdentifierExpression:
                          return ((IdentifierExpression)functionExpression).Identifier;
  
                      case Exp.BinaryOperatorExpression:
                          var operands = Flatten(functionExpression);
  
                          return operands.All(x => x.Type == Exp.IdentifierExpression) ?
                              FlattenAndJoinPath(functionExpression) :
                              functionExpression.ToString();
  
                      default:
                          return functionExpression.ToString();
                  }
              });
  
              PushFrame(callExpression, name, args);
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void PushFrame(
              AphidExpression callExpression,
              AphidExpression functionExpression,
              object arg)
          {
              var name = new Lazy<string>(() =>
              {
                  switch (functionExpression.Type)
                  {
                      case Exp.IdentifierExpression:
                          return ((IdentifierExpression)functionExpression).Identifier;
  
                      case Exp.BinaryOperatorExpression:
                          var operands = Flatten(functionExpression);
  
                          return operands.All(x => x.Type == Exp.IdentifierExpression) ?
                              FlattenAndJoinPath(functionExpression) :
                              functionExpression.ToString();
  
                      default:
                          return functionExpression.ToString();
                  }
              });
  
              PushFrame(callExpression, name, arg);
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void PushFrame(
              AphidExpression callExpression,
              Lazy<string> name,
              IEnumerable<object> args)
          {
  #if STRICT_OWNER_THREAD_VALIDATION
              VerifyOwnership();
  #endif
  
              while (_queuedFramePops > 0)
              {
                  _frames.Pop();
                  _queuedFramePops--;
              }
  
              _frames.Push(new AphidFrame(this, CurrentScope, callExpression, name, args));
  
  #if BINARY_FRAME_PERFORMANCE_TRACE || TEXT_FRAME_PERFORMANCE_TRACE
              var id = Thread.CurrentThread.ManagedThreadId;
  #endif
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
              _framePerformanceTrace.TraceText("{0:x8} > {1}\r\n", id, name.Value);
  #endif
  
  #if BINARY_FRAME_PERFORMANCE_TRACE
              // Todo: Pack enter/leave in as high order bit of thread id
              _framePerformanceBinaryWriter.WriteEnter(name.Value);
  #endif
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
              var sw = new Stopwatch();
              _frameStopwatchStack.Push(Tuple.Create(name.Value, sw));
              sw.Start();
  #endif
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void PushFrame(AphidExpression callExpression, Lazy<string> name, object arg)
          {
  #if STRICT_OWNER_THREAD_VALIDATION
              VerifyOwnership();
  #endif
              while (_queuedFramePops > 0)
              {
                  _frames.Pop();
                  _queuedFramePops--;
              }
  
              _frames.Push(new AphidFrame(this, CurrentScope, callExpression, name, arg));
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
              var id = Thread.CurrentThread.ManagedThreadId;
              _framePerformanceTrace.TraceText("{0:x8} > {1}\r\n", id, name.Value);
  #endif
  
  #if BINARY_FRAME_PERFORMANCE_TRACE
              // Todo: Pack enter/leave in as high order bit of thread id
              _framePerformanceBinaryWriter.WriteEnter(name.Value);
  #endif
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
              var sw = new Stopwatch();
              _frameStopwatchStack.Push(Tuple.Create(name.Value, sw));
              sw.Start();
  #endif
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void PushFrame(
              AphidExpression callExpression,
              string name,
              IEnumerable<object> args)
          {
  #if STRICT_OWNER_THREAD_VALIDATION
              VerifyOwnership();
  #endif
  
              while (_queuedFramePops > 0)
              {
                  _frames.Pop();
                  _queuedFramePops--;
              }
  
              _frames.Push(new AphidFrame(this, CurrentScope, callExpression, name, args));
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
              var id = Thread.CurrentThread.ManagedThreadId;
              _framePerformanceTrace.TraceText("{0:x8} > {1}\r\n", id, name);
  #endif
  
  #if BINARY_FRAME_PERFORMANCE_TRACE
              // Todo: Pack enter/leave in as high order bit of thread id
              _framePerformanceBinaryWriter.WriteEnter(name);
  #endif
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
              var sw = new Stopwatch();
              _frameStopwatchStack.Push(Tuple.Create(name, sw));
              sw.Start();
  #endif
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void PushFrame(in AphidFrame frame)
          {
  #if STRICT_OWNER_THREAD_VALIDATION
              VerifyOwnership();
  
  #endif
              while (_queuedFramePops > 0)
              {
                  _frames.Pop();
                  _queuedFramePops--;
              }
  
              _frames.Push(frame);
              //frame.Name.ToString();
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
              var id = Thread.CurrentThread.ManagedThreadId;
              _framePerformanceTrace.TraceText("{0:x8} > {1}\r\n", id, frame.Name);
  #endif
  
  #if BINARY_FRAME_PERFORMANCE_TRACE
              // Todo: Pack enter/leave in as high order bit of thread id
              _framePerformanceBinaryWriter.WriteEnter(frame.Name);
  #endif
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
              var sw = new Stopwatch();
              _frameStopwatchStack.Push(Tuple.Create(frame.Name, sw));
              sw.Start();
  #endif
          }
  
  #if BINARY_FRAME_PERFORMANCE_TRACE
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void PushFrameSilent(in AphidFrame frame)
          {
              while (_queuedFramePops > 0)
              {
                  _frames.Pop();
                  _queuedFramePops--;
              }
  
              _frames.Push(frame);
          }
  #endif
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void PopFrame()
          {
  #if TEXT_FRAME_PERFORMANCE_TRACE
              var tup = _frameStopwatchStack.Pop();
              tup.Item2.Stop();
              var id = Thread.CurrentThread.ManagedThreadId;
  #endif
  
  #if TEXT_FRAME_PERFORMANCE_TRACE
              _framePerformanceTrace.TraceText(
                  "{0:x8} < {1} - {2:n0} ticks / {3:n0}ms\r\n",
                  id,
                  tup.Item1,
                  tup.Item2.ElapsedTicks,
                  tup.Item2.ElapsedMilliseconds);
  #endif
  
  #if BINARY_FRAME_PERFORMANCE_TRACE
              _framePerformanceBinaryWriter.WriteLeave();
  #endif
              if (!_isInTryCatchFinally)
              {
                  while (_queuedFramePops > 0)
                  {
                      _frames.Pop();
                      _queuedFramePops--;
                  }
  
                  _frames.Pop();
              }
              else
              {
                  _queuedFramePops++;
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void PopQueuedFrames()
          {
              while (_queuedFramePops > 0)
              {
                  _frames.Pop();
                  _queuedFramePops--;
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void PopQueuedFrames(int offset)
          {
              while (_queuedFramePops > offset)
              {
                  _frames.Pop();
                  _queuedFramePops--;
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          internal AphidFrame CreateEntryFrame() =>
              OwnerThread != -1 ?
                  CreateNameFrame(GetEntryName()) :
                  new AphidFrame(
                      this,
                      CurrentScope,
                      CurrentExpression,
                      new Lazy<string>(() => GetEntryName()));
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private string GetEntryName() => Format("[Entrypoint (Thread 0x{0:X})]", OwnerThread);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidFrame CreateNameFrame(string name) => new(
              this,
              CurrentScope,
              CurrentExpression,
              name);
  
          #endregion
  
          #region Root Interpret Methods
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidObject InterpretStream(string code)
          {
              var ast = AphidParser.Parse(code);
  #if APHID_SET_CODE_VAR
              SetAstCode(ast);
  #endif
  
              var mutatedAst = MutatorGroups.GetStandard().Mutate(ast);
              Interpret(mutatedAst, resetIsReturning: true);
  
              return GetReturnValue(true);
  
  #pragma warning disable CS0162 // Unreachable code detected
              foreach (var exp in mutatedAst)
  #pragma warning restore CS0162 // Unreachable code detected
              {
                  InterpretExpression(exp);
  
                  if (_isReturning)
                  {
                      _isReturning = false;
                      return GetReturnValue(true);
                  }
              }
  
              return null;
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public AphidObject Interpret(AphidExpression expression)
          {
              CurrentStatement = expression;
  
  #if APHID_SET_CODE_VAR
              SetAstCode(new List<AphidExpression> { expression });
  #endif
              IdentifierExpression idExp;
              UnaryOperatorExpression unaryExp;
  
              if (((expression.Type == Exp.IdentifierExpression &&
                  (idExp = (IdentifierExpression)expression).Attributes.Count == 1) ||
                  (expression.Type == Exp.UnaryOperatorExpression &&
                  ((unaryExp = (UnaryOperatorExpression)expression).Operator == retKeyword) &&
                  unaryExp.Operand.Type == Exp.IdentifierExpression &&
                  (idExp = (IdentifierExpression)unaryExp.Operand).Attributes.Count == 1)) &&
                  idExp.Attributes[0].Identifier == AphidName.Var)
              {
                  var id = idExp.Identifier;
  
                  if (CurrentScope.ContainsKey(id))
                  {
                      throw CreateRuntimeException("Duplicated variable declaration: {0}", id);
                  }
  
                  CurrentScope.Add(id, InternedNull);
  
                  return null;
              }
  
              return InterpretExpression(expression);
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidObject InterpretExpression(AphidExpression expression)
          {
              CurrentExpression = expression;
  
  #if APHID_DEBUGGING_ENABLED
              HandleDebugging(expression);
  #endif
  
  #if STRICT_INDEX
              if (expression.Index == -1 || expression.Length == -1)
              {
                  throw new InvalidOperationException("Invalid index/length.");
              }
  #endif
  
  #if STRICT_OWNER_THREAD_VALIDATION
              VerifyOwnership();
  #endif
  
              if (OnInterpretExpression != null && !OnInterpretExpressionExecuting)
              {
                  OnInterpretExpressionExecuting = true;
                  try
                  {
                      AphidExecutionContext<AphidExpression> ctx = expression;
                      OnInterpretExpression(ctx);
  
                      if (ctx.IsHandled)
                      {
                          return ctx.Result;
                      }
                      else if (ctx.IsModified)
                      {
                          expression = ctx.Expression;
                      }
                  }
                  finally
                  {
                      OnInterpretExpressionExecuting = false;
                  }
              }
  
              switch (expression.Type)
              {
                  case Exp.BinaryOperatorExpression:
                      return (AphidObject)InterpretBinaryOperatorExpression((BinaryOperatorExpression)expression);
  
                  case Exp.BinaryOperatorBodyExpression:
                      return InterpretBinaryOperatorBodyExpression((BinaryOperatorBodyExpression)expression);
  
                  case Exp.ObjectExpression:
                      return InterpretObjectExpression((ObjectExpression)expression);
  
                  case Exp.StringExpression:
                      return InterpretStringExpression((StringExpression)expression);
  
                  case Exp.NumberExpression:
                      return InterpretNumberExpression((NumberExpression)expression);
  
                  case Exp.CallExpression:
                      return InterpretCallExpression((CallExpression)expression);
  
                  case Exp.IdentifierExpression:
                      return InterpretIdentifierExpression((IdentifierExpression)expression);
  
                  case Exp.FunctionExpression:
                      return InterpretFunctionExpression((FunctionExpression)expression);
  
                  case Exp.ArrayExpression:
                      return InterpretArrayExpression((ArrayExpression)expression);
  
                  case Exp.UnaryOperatorExpression:
                      return InterpretUnaryOperatorExpression((UnaryOperatorExpression)expression);
  
                  case Exp.BooleanExpression:
                      return InterpretBooleanExpression((BooleanExpression)expression);
  
                  case Exp.IfExpression:
                      return InterpretIfExpression((IfExpression)expression);
  
                  case Exp.ArrayAccessExpression:
                      return InterpretArrayAccessExpression((ArrayAccessExpression)expression);
  
                  case Exp.ForEachExpression:
                      return InterpretForEachExpression((ForEachExpression)expression);
  
                  case Exp.ForExpression:
                      return InterpretForExpression((ForExpression)expression);
  
                  case Exp.UsingExpression:
                      return InterpretUsingExpression((UsingExpression)expression);
  
                  case Exp.LockExpression:
                      return InterpretLockExpression((LockExpression)expression);
  
                  case Exp.LoadScriptExpression:
                      return InterpretLoadScriptExpression((LoadScriptExpression)expression);
  
                  case Exp.LoadLibraryExpression:
                      return InterpretLoadLibraryExpression((LoadLibraryExpression)expression);
  
                  case Exp.NullExpression:
                      return InternedNull;
  
                  case Exp.ContinueExpression:
                      return InterpretContinueExpression();
  
                  case Exp.BreakExpression:
                      return InterpretBreakExpression();
  
                  case Exp.PartialFunctionExpression:
                      return InterpretPartialFunctionExpression((PartialFunctionExpression)expression);
  
                  case Exp.ThisExpression:
                      return InterpretThisExpression();
  
                  case Exp.PatternMatchingExpression:
                      return InterpretPatternMatchingExpression((PatternMatchingExpression)expression);
  
                  case Exp.ExtendExpression:
                      InterpretExtendExpression((ExtendExpression)expression);
  
                      return null;
  
                  case Exp.WhileExpression:
                      InterpretWhileExpression((WhileExpression)expression);
  
                      return null;
  
                  case Exp.DoWhileExpression:
                      InterpretDoWhileExpression((DoWhileExpression)expression);
  
                      return null;
  
                  case Exp.TryExpression:
                      InterpretTryExpression((TryExpression)expression);
  
                      return null;
  
                  case Exp.TernaryOperatorExpression:
                      return InterpretTernaryOperatorExpression((TernaryOperatorExpression)expression);
  
                  case Exp.SwitchExpression:
                      InterpretSwitchExpression((SwitchExpression)expression);
  
                      return null;
  
                  case Exp.TextExpression:
                      InterpretTextExpression((TextExpression)expression);
  
                      return null;
  
                  case Exp.GatorOpenExpression:
                  case Exp.GatorCloseExpression:
                      return null;
  
                  case Exp.GatorEmitExpression:
                      InterpretGatorEmitExpression((GatorEmitExpression)expression);
  
                      return null;
  
                  case Exp.PartialOperatorExpression:
                      var partialOpExp = (PartialOperatorExpression)expression;
  
                      return InterpretPartialOperatorExpression(partialOpExp);
  
                  case Exp.ImplicitArgumentExpression:
                      return InterpretImplicitArgumentExpression();
  
                  case Exp.ImplicitArgumentsExpression:
                      return InterpretImplicitArgumentsExpression();
  
                  default:
                      throw CreateRuntimeException("Unexpected expression {0}", expression);
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private object InterpretAndUnwrap(AphidExpression expression) =>
              Unwrap(InterpretExpression(expression));
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void InterpretFile(string filename) => InterpretFile(filename, false);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void InterpretFile(string filename, bool isTextDocument)
          {
              var fullFilename = Loader.FindScriptFile(filename);
  
              if (fullFilename == null)
              {
                  throw CreateRuntimeException("Cannot find script {0}.", filename);
              }
  
              SetScriptFilename(fullFilename);
              var code = AphidScript.Read(filename);
              Interpret(code, filename, isTextDocument);
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void Interpret(string code) => Interpret(code, false);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void Interpret(string code, bool isTextDocument) =>
              Interpret(code, null, isTextDocument);
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void Interpret(string code, string filename, bool isTextDocument)
          {
              var ast = AphidParser.Parse(code, filename, isTextDocument);
  #if APHID_SET_CODE_VAR
              SetAstCode(ast);
  #endif
              Interpret(MutatorGroups.GetStandard().Mutate(ast));
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          public void Interpret(List<AphidExpression> expressions)
          {
              if (OwnerThread == -1)
              {
                  OwnerThread = Thread.CurrentThread.ManagedThreadId;
  #if APHID_SET_CODE_VAR
                  SetAstCode(expressions);
  #endif
                  Interpret(expressions, resetIsReturning: true);
              }
              else if (OwnerThread == Thread.CurrentThread.ManagedThreadId)
              {
  #if APHID_SET_CODE_VAR
                  SetAstCode(expressions);
  #endif
                  Interpret(expressions, resetIsReturning: true);
              }
              else
              {
                  // Todo: come up with more foolproof solution to this issue.
                  var child = AphidThread.CreateChild(this);
  
                  if (AphidErrorReporter.IsEnabled)
                  {
                      try
                      {
                          child.Interpret(expressions);
                      }
                      catch (Exception e)
                      {
                          AphidErrorReporter.Report(e, passThrough: true);
  
                          return;
                      }
                  }
                  else
                  {
                      child.Interpret(expressions);
                  }
  
                  child.Interpret(expressions);
  
                  var r = child.GetReturnValue(true);
  
                  if (r != null)
                  {
                      SetReturnValue(r);
                  }
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private void Interpret(List<AphidExpression> expressions, bool resetIsReturning)
          {
              if (OnInterpretBlock != null && !OnInterpretBlockExecuting)
              {
                  OnInterpretBlockExecuting = true;
  
                  try
                  {
                      var ctx = new AphidExecutionContext();
                      var result = OnInterpretBlock(expressions, ctx);
  
                      if (ctx.IsModified)
                      {
                          expressions = result;
                      }
  
                      if (ctx.IsHandled)
                      {
                          return;
                      }
                  }
                  finally
                  {
                      OnInterpretBlockExecuting = false;
                  }
              }
  
              if (!CurrentScope.ContainsKey(AphidName.Block))
              {
                  CurrentScope.Add(AphidName.Block, Scalar(expressions));
              }
  
              for (var i = 0; i < expressions.Count || _insertNextBuffer != null; i++)
              {
  #if APHID_DEBUGGING_ENABLED
                  _currentBlock = expressions;
  #endif
  
                  if (_insertNextBuffer != null)
                  {
                      expressions.InsertRange(i, _insertNextBuffer);
                      _insertNextBuffer = null;
                  }
  
                  var expression = expressions[i];
                  CurrentStatement = CurrentExpression = expression;
  
  #if EXPRESSION_HISTORY
                  if (!_isSteppingBack)
                  {
                      _expressionHistoryCount++;
  
                      if (++_expressionHistoryIndex == ExpressionHistorySize)
                      {
                          _expressionHistoryIndex = 0;
                      }
  
                      AphidObject scopeCopy;
  
                      if (CurrentScope != null)
                      {
                          //var num = 0;
                          scopeCopy = Complex();
  
                          var dst = scopeCopy;
                          var src = CurrentScope;
  
                          while (true)
                          {
                              foreach (var kvp in src)
                              {
                                  dst.Add(
                                      kvp.Key,
                                      kvp.Value == null ? null :
                                      kvp.Value.IsComplex ? Complex(kvp.Value) :
                                      Scalar(kvp.Value.Value));
                              }
  
                              //dst.Add("$copy", Scalar(num++));
  
                              if (src.Parent != null)
                              {
                                  var p = Scope();
                                  dst.Parent = p;
                                  dst["$parent"] = p;
                                  dst = p;
                                  src = src.Parent;
                              }
                              else
                              {
                                  break;
                              }
                          }
                      }
                      else
                      {
                          scopeCopy = null;
                      }
  
  
                      _expressionHistory[_expressionHistoryIndex] = new ExpressionHistoryRecord(
                          CurrentStatement,
                          expressions,
                          i,
                          scopeCopy,
                          GetStackTrace(-1));
                  }
                  else
                  {
                      _isSteppingBack = false;
                  }
  #endif
  
                  if (OnInterpretStatement != null && !OnInterpretStatementExecuting)
                  {
                      OnInterpretStatementExecuting = true;
  
                      try
                      {
                          AphidExecutionContext<AphidExpression> ctx = expression;
                          OnInterpretStatement(ctx);
  
                          if (ctx.IsHandled)
                          {
                              continue;
                          }
                          else if (ctx.IsModified)
                          {
                              expression = ctx.Expression;
                          }
                      }
                      finally
                      {
                          OnInterpretStatementExecuting = false;
                      }
                  }
  
                  if (expression.Type == Exp.IdentifierExpression)
                  {
  #if APHID_DEBUGGING_ENABLED
  #if EXPRESSION_HISTORY
                      try
                      {
  #endif
                          HandleDebugging(expression);
  #if EXPRESSION_HISTORY
                      }
                      catch (StepBackException)
                      {
                          var rec = _expressionHistory[_expressionHistoryIndex];
                          expressions = rec.Block;
                          i = rec.BlockIndex - 1;
                          CurrentStatement = CurrentExpression = rec.Statement;
  
                          if (_singleStepReset != null)
                          {
                              _singleStepReset.Reset();
                          }
                          else
                          {
                              _singleStepReset = new AutoResetEvent(false);
                          }
  
                          BreakExecution(CurrentStatement);
                          _isSingleStepping = true;
                          continue;
                      }
  #endif
  #endif
  
                      var idExp = (IdentifierExpression)expression;
                      var id = idExp.Identifier;
                      List<IdentifierExpression> attrs;
  
                      if (CurrentScope.ContainsKey(id))
                      {
                          throw CreateRuntimeException("Duplicated variable declaration: {0}", id);
                      }
                      else if (StrictMode &&
                          ((attrs = idExp.Attributes).Count == 0 ||
                          attrs[0].Identifier != AphidName.Var))
                      {
                          throw CreateStrictModeException(id);
                      }
  
                      CurrentScope.Add(id, InternedNull);
                  }
                  else
                  {
  #if APHID_DEBUGGING_ENABLED && EXPRESSION_HISTORY
                      try
                      {
  #endif
                          InterpretExpression(expression);
  #if APHID_DEBUGGING_ENABLED && EXPRESSION_HISTORY
                      }
                      catch (StepBackException)
                      {
                          var rec = _expressionHistory[_expressionHistoryIndex];
                          expressions = rec.Block;
                          i = rec.BlockIndex - 1;
                          CurrentStatement = CurrentExpression = rec.Statement;
  
                          if (_singleStepReset != null)
                          {
                              _singleStepReset.Reset();
                          }
                          else
                          {
                              _singleStepReset = new AutoResetEvent(false);
                          }
  
                          BreakExecution(CurrentStatement);
                          _isSingleStepping = true;
                          continue;
                      }
  #endif
                  }
  
                  if (_isBreaking || _isContinuing)
                  {
                      break;
                  }
                  else if (_isReturning)
                  {
                      if (resetIsReturning)
                      {
                          _isReturning = false;
                      }
  
                      break;
                  }
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private void InterpretBlock(List<AphidExpression> block)
          {
              EnterScope();
  
              try
              {
                  Interpret(block, false);
              }
              finally
              {
                  LeaveScope(true);
              }
          }
  
          #endregion
  
          #region Node Specific Interpret Methods
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidObject InterpretInteropNewExpression(AphidExpression operand)
          {
              switch (operand.Type)
              {
                  case Exp.CallExpression:
                      var call = (CallExpression)operand;
  
                      var args = new object[call.Args.Count];
  
                      for (var i = 0; i < args.Length; i++)
                      {
                          args[i] = DeepUnwrap(InterpretExpression(call.Args[i]));
                      }
  
                      PushFrame(operand, call.FunctionExpression, args);
  
                      try
                      {
                          var typeObj = Unwrap(InterpretExpression(call.FunctionExpression));
  
                          if (typeObj == null)
                          {
                              throw CreateRuntimeException(
                                  "Could not resolve type {0}.",
                                  call.FunctionExpression);
                          }
                          else if (!typeof(Type).IsAssignableFrom(typeObj.GetType()))
                          {
                              throw CreateRuntimeException(
                                  "Expression '{0}' resolved to '{1}', expected type.",
                                  call.FunctionExpression,
                                  typeObj);
                          }
  
                          var type = (Type)typeObj;
  
                          object result;
                          AphidObject obj;
  
                          if (!type.IsValueType || args.Length > 0)
                          {
                              var ctor = InteropMethodResolver.Resolve(
                                  type.GetConstructors(),
                                  args);
  
                              var convertedArgs = TypeConverter.Convert(
                                  ctor.Arguments,
                                  ctor.GenericArguments);
  
                              result = ((ConstructorInfo)ctor.Method).Invoke(convertedArgs);
  
                              obj = type != typeof(AphidObject) ? Scalar(result) : (AphidObject)result;
                          }
                          else
                          {
                              obj = Scalar(result = Activator.CreateInstance(type));
                          }
  
                          var extension = TryResolve(
                              CurrentScope,
                              obj,
                              GetCtorName(type.FullName),
                              false,
                              isCtor: true,
                              isDynamic: false,
                              returnRef: false);
  
                          if (extension != null)
                          {
                              if (extension.Value is AphidFunction func)
                              {
                                  var obj2 = CallFunction(func, obj);
  
                                  if (obj2 != null)
                                  {
                                      obj = obj2;
                                  }
                              }
                              else
                              {
                                  obj = extension;
                              }
                          }
  
                          return obj;
                      }
  #if APHID_FRAME_ADD_DATA || APHID_FRAME_CATCH_POP
  #if APHID_FRAME_ADD_DATA
                      catch (Exception e)
  #else
                      catch
  #endif
                      {
                          if (e.Source != AphidName.DebugInterpreter)
                          {
                              e.Source = AphidName.DebugInterpreter;
  #if APHID_FRAME_CATCH_POP
                              while (_queuedFramePops > 0)
                              {
                                  _frames.Pop();
                                  _queuedFramePops--;
                              }
  #endif
  
  #if APHID_FRAME_ADD_DATA
                              e.Data.Add(AphidName.Interpreter, this);
                              e.Data.Add(AphidName.FramesKey, GetRawStackTrace());
  #if TRACK_PREVIOUS_SCOPE
                              e.Data.Add(AphidName.Scope, PreviousScope);
  #endif
  #endif
                          }
  
                          throw;
                      }
  #endif
                      finally
                      {
                          PopFrame();
                      }
  
                  default:
                      throw CreateRuntimeException("Operand not supported in new expression: {0}", operand);
              }
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidObject InterpretFunctionExpression(FunctionExpression expression)
          {
              var args = new string[expression.Args.Count];
  
              for (var i = 0; i < args.Length; i++)
              {
                  args[i] = ((IdentifierExpression)expression.Args[i]).Identifier;
              }
  
              return Scalar(new AphidFunction(args, expression.Body, CurrentScope));
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidObject InterpretArrayExpression(ArrayExpression expression)
          {
              var list = new List<AphidObject>(expression.Elements.Count);
  
              for (var i = 0; i < expression.Elements.Count; i++)
              {
                  var element = InterpretExpression(expression.Elements[i]);
  
                  if (element is AphidObject ao)
                  {
                      if (ao.IsComplex)
                      {
                          list.Add(ao);
                      }
                      else
                      {
                          list.Add(Scalar(ao.Value));
                      }
                  }
                  else
                  {
                      list.Add(Scalar(element));
                  }
              }
  
              return Scalar(list);
          }
  
          [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), MethodImpl(MethodImplOptions.AggressiveInlining)]
          private AphidObject InterpretUnaryOperatorExpression(UnaryOperatorExpression expression)
          {
              if (!expression.IsPostfix)
              {
                  switch (expression.Operator)
                  {
                      case AdditionOperator:
                          return InterpretExpression(expression.Operand);
  
                      case MinusOperator:
                          var val = Unwrap(InterpretExpression(expression.Operand));
  
                          return val is decimal d
                              ? Scalar(d * -1)
                              : throw CreateRuntimeException(
                                  "Unary operator '-' expects number, {0} was provided instead.",
                                  val.GetType());
  
  
                      case ComplementOperator:
                          val = InterpretAndUnwrap(expression.Operand);
                          return Scalar((decimal)~ToUInt64(ValueHelper.AssertNumber(val, "unary operator '~'")));
  
                      case throwKeyword:
                          var exceptionObj = Unwrap(InterpretExpression(expression.Operand));
  
                          throw exceptionObj switch
                          {
                              Exception exception => exception,
                              string message => CreateRuntimeException(message),
                              _ => CreateRuntimeException(
                                  "Cannot throw value of type {0}, from expression {1} " +
                                  "expected Exception or string.",
                                  exceptionObj ?? "null",
                                  expression),
                          };
                      case retKeyword:
                          SetReturnValue(InterpretExpression(expression.Operand));
                          _isReturning = true;
                          return null;
  
                      case deleteKeyword:
                          var operand = ((IdentifierExpression)expression.Operand).Identifier;
                          return Scalar(CurrentScope.TryResolveAndRemove(operand));
  
                      case NotOperator:
                          return Scalar(!(bool)InterpretExpression(expression.Operand).Value);
  
                      case IncrementOperator:
                          var obj = InterpretExpression(expression.Operand);
                          obj.Value = ((decimal)obj.Value) + 1;
                          return obj;
  
                      case DecrementOperator:
                          obj = InterpretExpression(expression.Operand);
                          obj.Value = ((decimal)obj.Value) - 1;
                          return obj;
  
                      case DistinctOperator:
                          var result = ValueHelper
                              .UnwrapIEnumerableObject(InterpretExpression(expression.Operand))
                              .Select(Unwrap)
                              .Distinct()
                              .Select(Wrap) // To maintain backwards compat with Aphid
                              .ToList()
                              ;                // list extension such as __list.count().
  
                          return Scalar(result);
  
                      case PostfixCountOperator:
                          return Scalar(
                              ValueHelper
                                  .UnwrapIEnumerableObject(InterpretExpression(expression.Operand))
                                  .Count());
  
                      case PostfixFirstOperator:
                          return Wrap(
                              ValueHelper
                                  .UnwrapIEnumerableObject(InterpretExpression(expression.Operand))
                                  .First());
  
                      case PostfixLastOperator:
                          return Wrap(
                              ValueHelper
                                  .UnwrapIEnumerableObject(InterpretExpression(expression.Operand))
                                  .Last());
  
                      case PostfixOrderOperator:
                          return Wrap(
                              ValueHelper
                                  .UnwrapIEnumerableObject(InterpretExpression(expression.Operand))
                                  .OrderBy(Unwrap));
  
                      case PostfixOrderDescendingOperator:
                          return Wrap(
                              ValueHelper
                                  .UnwrapIEnumerableObject(InterpretExpression(expression.Operand))
                                  .OrderByDescending(Unwrap));
  
                      //return Scalar(list.Distinct(_comparer).ToList());
  
                      case usingKeyword:
                          AddImport(FlattenAndJoinPath(expression.Operand));
  
                          return null;
  
                      case newKeyword:
                          return InterpretInteropNewExpression(expression.Operand);
  
                      case loadKeyword:
                          // Todo: make more robust by searching application dir,
                          // script dir, etc.
                          Assembly asm = null;
                          string path;
  
                          switch (expression.Operand.Type)
                          {
                              case Exp.IdentifierExpression:
                              case Exp.BinaryOperatorExpression:
  #pragma warning disable CS0618 // 'Assembly.LoadWithPartialName(string)' is obsolete: 'This method has been deprecated. Please use Assembly.Load() instead. http://go.microsoft.com/fwlink/?linkid=14202'
                                  asm = Assembly.LoadWithPartialName(
                                      path = FlattenAndJoinPath(expression.Operand));
  #pragma warning restore CS0618 // 'Assembly.LoadWithPartialName(string)' is obsolete: 'This method has been deprecated. Please use Assembly.Load() instead. http://go.microsoft.com/fwlink/?linkid=14202'
                                  break;
  
                              case Exp.StringExpression:
                                  if (File.Exists(path = Path.GetFullPath(
                                      StringParser.Parse(
                                          ((StringExpression)expression.Operand).Value))))
                                  {
                                      asm = Assembly.LoadFrom(path);
                                  }
  
                                  break;
                          }
  
                          if (asm == null)
                          {
                              // Todo: safely deref member expression to avoid
                              // null ref exception on fallback.
                              var loadOperand = InterpretExpression(expression.Operand);
                              var unwrappedPath = Unwrap((object)loadOperand);
  
                              if (unwrappedPath == null)
                              {
                                  return InternedNull;
                              }
  
                              if (File.Exists(path = unwrappedPath.ToString()))
                              {
                                  asm = Assembly.LoadFrom(path);
                              }
                          }
  
                          return Scalar(asm);
  
                      case InteropOperator:
                          return GetInteropAttribute(expression.Operand) switch
                          {
                              null => expression.Operand.Type switch
                              {
                                  Exp.CallExpression => CallStaticInteropFunction(
                                      (CallExpression)expression.Operand),
                                  Exp.BinaryOperatorExpression => InterpretMemberInteropExpression(
                                      null,
                                      (BinaryOperatorExpression)expression.Operand),
                                  _ => throw new NotImplementedException(),
                              },
                              _ => throw new NotImplementedException(),
                          };
  
                      #region Custom Operator Cases
                      case AphidTokenType.CustomOperator000:
                      case AphidTokenType.CustomOperator001:
                      case AphidTokenType.CustomOperator002:
                      case AphidTokenType.CustomOperator003:
                      case AphidTokenType.CustomOperator004:
                      case AphidTokenType.CustomOperator005:
                      case AphidTokenType.CustomOperator006:
                      case AphidTokenType.CustomOperator007:
                      case AphidTokenType.CustomOperator008:
                      case AphidTokenType.CustomOperator009:
                      case AphidTokenType.CustomOperator010:
                      case AphidTokenType.CustomOperator011:
                      case AphidTokenType.CustomOperator012:
                      case AphidTokenType.CustomOperator013:
                      case AphidTokenType.CustomOperator014:
                      case AphidTokenType.CustomOperator015:
                      case AphidTokenType.CustomOperator016:
                      case AphidTokenType.CustomOperator017:
                      case AphidTokenType.CustomOperator018:
                      case AphidTokenType.CustomOperator019:
                      case AphidTokenType.CustomOperator020:
                      case AphidTokenType.CustomOperator021:
                      case AphidTokenType.CustomOperator022:
                      case AphidTokenType.CustomOperator023:
                      case AphidTokenType.CustomOperator024:
                      case AphidTokenType.CustomOperator025:
                      case AphidTokenType.CustomOperator026:
                      case AphidTokenType.CustomOperator027:
                      case AphidTokenType.CustomOperator028:
                      case AphidTokenType.CustomOperator029:
                      case AphidTokenType.CustomOperator030:
                      case AphidTokenType.CustomOperator031:
                      case AphidTokenType.CustomOperator032:
                      case AphidTokenType.CustomOperator033:
                      case AphidTokenType.CustomOperator034:
                      case AphidTokenType.CustomOperator035:
                      case AphidTokenType.CustomOperator036:
                      case AphidTokenType.CustomOperator037:
                      case AphidTokenType.CustomOperator038:
                      case AphidTokenType.CustomOperator039:
                      case AphidTokenType.CustomOperator040:
                      case AphidTokenType.CustomOperator041:
                      case AphidTokenType.CustomOperator042:
                      case AphidTokenType.CustomOperator043:
                      case AphidTokenType.CustomOperator044:
                      case AphidTokenType.CustomOperator045:
                      case AphidTokenType.CustomOperator046:
                      case AphidTokenType.CustomOperator047:
                      case AphidTokenType.CustomOperator048:
                      case AphidTokenType.CustomOperator049:
                      case AphidTokenType.CustomOperator050:
                      case AphidTokenType.CustomOperator051:
                      case AphidTokenType.CustomOperator052:
                      case AphidTokenType.CustomOperator053:
                      case AphidTokenType.CustomOperator054:
                      case AphidTokenType.CustomOperator055:
                      case AphidTokenType.CustomOperator056:
                      case AphidTokenType.CustomOperator057:
                      case AphidTokenType.CustomOperator058:
                      case AphidTokenType.CustomOperator059:
                      case AphidTokenType.CustomOperator060:
                      case AphidTokenType.CustomOperator061:
                      case AphidTokenType.CustomOperator062:
                      case AphidTokenType.CustomOperator063:
                      case AphidTokenType.CustomOperator064:
                      case AphidTokenType.CustomOperator065:
                      case AphidTokenType.CustomOperator066:
                      case AphidTokenType.CustomOperator067:
                      case AphidTokenType.CustomOperator068:
                      case AphidTokenType.CustomOperator069:
                      case AphidTokenType.CustomOperator070:
                      case AphidTokenType.CustomOperator071:
                      case AphidTokenType.CustomOperator072:
                      case AphidTokenType.CustomOperator073:
                      case AphidTokenType.CustomOperator074:
                      case AphidTokenType.CustomOperator075:
                      case AphidTokenType.CustomOperator076:
                      case AphidTokenType.CustomOperator077:
                      case AphidTokenType.CustomOperator078:
                      case AphidTokenType.CustomOperator079:
                      case AphidTokenType.CustomOperator080:
                      case AphidTokenType.CustomOperator081:
                      case AphidTokenType.CustomOperator082:
                      case AphidTokenType.CustomOperator083:
                      case AphidTokenType.CustomOperator084:
                      case AphidTokenType.CustomOperator085:
                      case AphidTokenType.CustomOperator086:
                      case AphidTokenType.CustomOperator087:
                      case AphidTokenType.CustomOperator088:
                      case AphidTokenType.CustomOperator089:
                      case AphidTokenType.CustomOperator090:
                      case AphidTokenType.CustomOperator091:
                      case AphidTokenType.CustomOperator092:
                      case AphidTokenType.CustomOperator093:
                      case AphidTokenType.CustomOperator094:
                      case AphidTokenType.CustomOperator095:
                      case AphidTokenType.CustomOperator096:
                      case AphidTokenType.CustomOperator097:
                      case AphidTokenType.CustomOperator098:
                      case AphidTokenType.CustomOperator099:
                      case AphidTokenType.CustomOperator100:
                      case AphidTokenType.CustomOperator101:
                      case AphidTokenType.CustomOperator102:
                      case AphidTokenType.CustomOperator103:
                      case AphidTokenType.CustomOperator104:
                      case AphidTokenType.CustomOperator105:
                      case AphidTokenType.CustomOperator106:
                      case AphidTokenType.CustomOperator107:
                      case AphidTokenType.CustomOperator108:
                      case AphidTokenType.CustomOperator109:
                      case AphidTokenType.CustomOperator110:
                      case AphidTokenType.CustomOperator111:
                      case AphidTokenType.CustomOperator112:
                      case AphidTokenType.CustomOperator113:
                      case AphidTokenType.CustomOperator114:
                      case AphidTokenType.CustomOperator115:
                      case AphidTokenType.CustomOperator116:
                      case AphidTokenType.CustomOperator117:
                      case AphidTokenType.CustomOperator118:
                      case AphidTokenType.CustomOperator119:
                      case AphidTokenType.CustomOperator120:
                      case AphidTokenType.CustomOperator121:
                      case AphidTokenType.CustomOperator122:
                      case AphidTokenType.CustomOperator123:
                      case AphidTokenType.CustomOperator124:
                      case AphidTokenType.CustomOperator125:
                      case AphidTokenType.CustomOperator126:
                      case AphidTokenType.CustomOperator127:
                      case AphidTokenType.CustomOperator128:
                      case AphidTokenType.CustomOperator129:
                      case AphidTokenType.CustomOperator130:
                      case AphidTokenType.CustomOperator131:
                      case AphidTokenType.CustomOperator132:
                      case AphidTokenType.CustomOperator133:
                      case AphidTokenType.CustomOperator134:
                      case AphidTokenType.CustomOperator135:
                      case AphidTokenType.CustomOperator136:
                      case AphidTokenType.CustomOperator137:
                      case AphidTokenType.CustomOperator138:
                      case AphidTokenType.CustomOperator139:
                      case AphidTokenType.CustomOperator140:
                      case AphidTokenType.CustomOperator141:
                      case AphidTokenType.CustomOperator142:
                      case AphidTokenType.CustomOperator143:
                      case AphidTokenType.CustomOperator144:
                      case AphidTokenType.CustomOperator145:
                      case AphidTokenType.CustomOperator146:
                      case AphidTokenType.CustomOperator147:
                      case AphidTokenType.CustomOperator148:
                      case AphidTokenType.CustomOperator149:
                      case AphidTokenType.CustomOperator150:
                      case AphidTokenType.CustomOperator151:
                      case AphidTokenType.CustomOperator152:
                      case AphidTokenType.CustomOperator153:
                      case AphidTokenType.CustomOperator154:
                      case AphidTokenType.CustomOperator155:
                      case AphidTokenType.CustomOperator156:
                      case AphidTokenType.CustomOperator157:
                      case AphidTokenType.CustomOperator158:
                      case AphidTokenType.CustomOperator159:
                      case AphidTokenType.CustomOperator160:
                      case AphidTokenType.CustomOperator161:
                      case AphidTokenType.CustomOperator162:
                      case AphidTokenType.CustomOperator163:
                      case AphidTokenType.CustomOperator164:
                      case AphidTokenType.CustomOperator165:
                      case AphidTokenType.CustomOperator166:
                      case AphidTokenType.CustomOperator167:
                      case AphidTokenType.CustomOperator168:
                      case AphidTokenType.CustomOperator169:
                      case AphidTokenType.CustomOperator170:
                      case AphidTokenType.CustomOperator171:
                      case AphidTokenType.CustomOperator172:
                      case AphidTokenType.CustomOperator173:
                      case AphidTokenType.CustomOperator174:
                      case AphidTokenType.CustomOperator175:
                      case AphidTokenType.CustomOperator176:
                      case AphidTokenType.CustomOperator177:
                      case AphidTokenType.CustomOperator178:
                      case AphidTokenType.CustomOperator179:
                      case AphidTokenType.CustomOperator180:
                      case AphidTokenType.CustomOperator181:
                      case AphidTokenType.CustomOperator182:
                      case AphidTokenType.CustomOperator183:
                      case AphidTokenType.CustomOperator184:
                      case AphidTokenType.CustomOperator185:
                      case AphidTokenType.CustomOperator186:
                      case AphidTokenType.CustomOperator187:
                      case AphidTokenType.CustomOperator188:
                      case AphidTokenType.CustomOperator189:
                      case AphidTokenType.CustomOperator190:
                      case AphidTokenType.CustomOperator191:
                      case AphidTokenType.CustomOperator192:
                      case AphidTokenType.CustomOperator193:
                      case AphidTokenType.CustomOperator194:
                      case AphidTokenType.CustomOperator195:
                      case AphidTokenType.CustomOperator196:
                      case AphidTokenType.CustomOperator197:
                      case AphidTokenType.CustomOperator198:
                      case AphidTokenType.CustomOperator199:
                      case AphidTokenType.CustomOperator200:
                      case AphidTokenType.CustomOperator201:
                      case AphidTokenType.CustomOperator202:
                      case AphidTokenType.CustomOperator203:
                      case AphidTokenType.CustomOperator204:
                      case AphidTokenType.CustomOperator205:
                      case AphidTokenType.CustomOperator206:
                      case AphidTokenType.CustomOperator207:
                      case AphidTokenType.CustomOperator208:
                      case AphidTokenType.CustomOperator209:
                      case AphidTokenType.CustomOperator210:
                      case AphidTokenType.CustomOperator211:
                      case AphidTokenType.CustomOperator212:
                      case AphidTokenType.CustomOperator213:
                      case AphidTokenType.CustomOperator214:
                      case AphidTokenType.CustomOperator215:
                      case AphidTokenType.CustomOperator216:
                      case AphidTokenType.CustomOperator217:
                      case AphidTokenType.CustomOperator218:
                      case AphidTokenType.CustomOperator219:
                      case AphidTokenType.CustomOperator220:
                      case AphidTokenType.CustomOperator221:
                      case AphidTokenType.CustomOperator222:
                      case AphidTokenType.CustomOperator223:
                      case AphidTokenType.CustomOperator224:
                      case AphidTokenType.CustomOperator225:
                      case AphidTokenType.CustomOperator226:
                      case AphidTokenType.CustomOperator227:
                      case AphidTokenType.CustomOperator228:
                      case AphidTokenType.CustomOperator229:
                      case AphidTokenType.CustomOperator230:
                      case AphidTokenType.CustomOperator231:
                      case AphidTokenType.CustomOperator232:
                      case AphidTokenType.CustomOperator233:
                      case AphidTokenType.CustomOperator234:
                      case AphidTokenType.CustomOperator235:
                      case AphidTokenType.CustomOperator236:
                      case AphidTokenType.CustomOperator237:
                      case AphidTokenType.CustomOperator238:
                      case AphidTokenType.CustomOperator239:
                      case AphidTokenType.CustomOperator240:
                      case AphidTokenType.CustomOperator241:
                      case AphidTokenType.CustomOperator242:
                      case AphidTokenType.CustomOperator243:
                      case AphidTokenType.CustomOperator244:
                      case AphidTokenType.CustomOperator245:
                      case AphidTokenType.CustomOperator246:
                      case AphidTokenType.CustomOperator247:
                      case AphidTokenType.CustomOperator248:
                      case AphidTokenType.CustomOperator249:
                      case AphidTokenType.CustomOperator250:
                      case AphidTokenType.CustomOperator251:
                      case AphidTokenType.CustomOperator252:
                      case AphidTokenType.CustomOperator253:
                      case AphidTokenType.CustomOperator254:
                      case AphidTokenType.CustomOperator255:
                      case AphidTokenType.CustomOperator256:
                      case AphidTokenType.CustomOperator257:
                      case AphidTokenType.CustomOperator258:
                      case AphidTokenType.CustomOperator259:
                      case AphidTokenType.CustomOperator260:
                      case AphidTokenType.CustomOperator261:
                      case AphidTokenType.CustomOperator262:
                      case AphidTokenType.CustomOperator263:
                      case AphidTokenType.CustomOperator264:
                      case AphidTokenType.CustomOperator265:
                      case AphidTokenType.CustomOperator266:
                      case AphidTokenType.CustomOperator267:
                      case AphidTokenType.CustomOperator268:
                      case AphidTokenType.CustomOperator269:
                      case AphidTokenType.CustomOperator270:
                      case AphidTokenType.CustomOperator271:
                      case AphidTokenType.CustomOperator272:
                      case AphidTokenType.CustomOperator273:
                      case AphidTokenType.CustomOperator274:
                      case AphidTokenType.CustomOperator275:
                      case AphidTokenType.CustomOperator276:
                      case AphidTokenType.CustomOperator277:
                      case AphidTokenType.CustomOperator278:
                      case AphidTokenType.CustomOperator279:
                      case AphidTokenType.CustomOperator280:
                      case AphidTokenType.CustomOperator281:
                      case AphidTokenType.CustomOperator282:
                      case AphidTokenType.CustomOperator283:
                      case AphidTokenType.CustomOperator284:
                      case AphidTokenType.CustomOperator285:
                      case AphidTokenType.CustomOperator286:
                      case AphidTokenType.CustomOperator287:
                      case AphidTokenType.CustomOperator288:
                      case AphidTokenType.CustomOperator289:
                      case AphidTokenType.CustomOperator290:
                      case AphidTokenType.CustomOperator291:
                      case AphidTokenType.CustomOperator292:
                      case AphidTokenType.CustomOperator293:
                      case AphidTokenType.CustomOperator294:
                      case AphidTokenType.CustomOperator295:
                      case AphidTokenType.CustomOperator296:
                      case AphidTokenType.CustomOperator297:
                      case AphidTokenType.CustomOperator298:
                      case AphidTokenType.CustomOperator299:
                      case AphidTokenType.CustomOperator300:
                      case AphidTokenType.CustomOperator301:
                      case AphidTokenType.CustomOperator302:
                      case AphidTokenType.CustomOperator303:
                      case AphidTokenType.CustomOperator304:
                      case AphidTokenType.CustomOperator305:
                      case AphidTokenType.CustomOperator306:
                      case AphidTokenType.CustomOperator307:
                      case AphidTokenType.CustomOperator308:
                      case AphidTokenType.CustomOperator309:
                      case AphidTokenType.CustomOperator310:
                      case AphidTokenType.CustomOperator311:
                      case AphidTokenType.CustomOperator312:
                      case AphidTokenType.CustomOperator313:
                      case AphidTokenType.CustomOperator314:
                      case AphidTokenType.CustomOperator315:
                      case AphidTokenType.CustomOperator316:
                      #endregion
                          return InterpretCustomUnaryOperator(expression);
  
                      default:
                          throw CreateUnaryOperatorException(expression);
                  }
              }
              else
              {
                  switch (expression.Operator)
                  {
                      case IncrementOperator:
                          var obj = InterpretExpression(expression.Operand);
                          var v = obj.Value;
                          obj.Value = ((decimal)obj.Value) + 1;
                          return Scalar(v);
  
                      case DecrementOperator:
                          obj = InterpretExpression(expression.Operand);
                          v = obj.Value;
                          obj.Value = ((decimal)obj.Value) - 1;
                          return Scalar(v);
  
                      case definedKeyword:
                          switch (expression.Operand.Type)
                          {
                              case Exp.IdentifierExpression:
                                  return CurrentScope.IsDefined(((IdentifierExpression)expression.Operand).Identifier) ? InternedTrue : InternedFalse;
  
  
                              case Exp.BinaryOperatorExpression:
                                  try
                                  {
                                      var memberRefObj = Unwrap(
                                          InterpretBinaryOperatorExpression(
                                              (BinaryOperatorExpression)expression.Operand,
                                              returnRef: true));
  
                                      switch (memberRefObj)
                                      {
                                          case AphidRef memberRef:
                                              var o = memberRef.Object;
  
                                              return o.IsComplex && o.IsDefined(memberRef.Name) ? InternedTrue : InternedFalse;
  
                                          default:
                                              return memberRefObj is AphidInteropReference ? InternedTrue : InternedFalse;
  
                                      }
                                  }
                                  catch
                                  {
                                      return InternedFalse;
                                  }
  
                              case Exp.ArrayAccessExpression:
                                  var arrayExp = (ArrayAccessExpression)expression.Operand;
  
                                  if (arrayExp.KeyExpressions.Count != 1)
                                  {
                                      throw CreateRuntimeException("Index expected.");
                                  }
  
                                  var keyObj = InterpretExpression(arrayExp.KeyExpressions[0]).Value;
  
                                  if (keyObj is string key)
                                  {
                                      var aphidObj = InterpretExpression(arrayExp.ArrayExpression);
  
                                      if (aphidObj.IsScalar)
                                      {
  
gt:                                         return aphidObj.Value != null &&