// @TODO: Rewrite using C# 7 features
        protected virtual void _Generate(AstNodeStmAssign assign)
        {
            //Assign.Local.LocalBuilder.LocalIndex
            var astNodeExprLocal             = assign.LeftValue as AstNodeExprLocal;
            var astNodeExprArgument          = assign.LeftValue as AstNodeExprArgument;
            var astNodeExprFieldAccess       = assign.LeftValue as AstNodeExprFieldAccess;
            var astNodeExprStaticFieldAccess = assign.LeftValue as AstNodeExprStaticFieldAccess;
            var astNodeExprIndirect          = assign.LeftValue as AstNodeExprIndirect;
            var astNodeExprArrayAccess       = assign.LeftValue as AstNodeExprArrayAccess;
            var astNodeExprPropertyAccess    = assign.LeftValue as AstNodeExprPropertyAccess;
            var astNodeExprSetGetLValue      = assign.LeftValue as AstNodeExprSetGetLValue;


            if (astNodeExprLocal != null)
            {
                Generate(assign.Value);
                Emit(OpCodes.Stloc, _GetLocalBuilderFromAstLocal(astNodeExprLocal.AstLocal));
            }
            else if (astNodeExprArgument != null)
            {
                Generate(assign.Value);
                Emit(OpCodes.Starg, astNodeExprArgument.AstArgument.Index);
            }
            else if (astNodeExprFieldAccess != null)
            {
                Generate(astNodeExprFieldAccess.Instance);
                Generate(assign.Value);
                Emit(OpCodes.Stfld, astNodeExprFieldAccess.Field);
            }
            else if (astNodeExprStaticFieldAccess != null)
            {
                Generate(assign.Value);
                Emit(OpCodes.Stsfld, astNodeExprStaticFieldAccess.Field);
            }
            else if (astNodeExprArrayAccess != null)
            {
                Generate(astNodeExprArrayAccess.ArrayInstance);
                Generate(astNodeExprArrayAccess.Index);
                Generate(assign.Value);
                Emit(OpCodes.Stelem, astNodeExprArrayAccess.ArrayInstance.Type.GetElementType());
            }
            else if (astNodeExprIndirect != null)
            {
                var pointerType = AstUtils.GetSignedType(astNodeExprIndirect.PointerExpression.Type.GetElementType());

                Generate(astNodeExprIndirect.PointerExpression);
                Generate(assign.Value);

                if (pointerType == typeof(sbyte))
                {
                    Emit(OpCodes.Stind_I1);
                }
                else if (pointerType == typeof(short))
                {
                    Emit(OpCodes.Stind_I2);
                }
                else if (pointerType == typeof(int))
                {
                    Emit(OpCodes.Stind_I4);
                }
                else if (pointerType == typeof(long))
                {
                    Emit(OpCodes.Stind_I8);
                }
                else if (pointerType == typeof(float))
                {
                    Emit(OpCodes.Stind_R4);
                }
                else if (pointerType == typeof(double))
                {
                    Emit(OpCodes.Stind_R8);
                }
                else if (pointerType == typeof(bool))
                {
                    Emit(OpCodes.Stind_I1);
                }
                else
                {
                    throw new NotImplementedException("Can't store indirect value");
                }
            }
            else if (astNodeExprPropertyAccess != null)
            {
                Generate(astNodeExprPropertyAccess.Instance);
                Generate(assign.Value);
                Emit(OpCodes.Callvirt, astNodeExprPropertyAccess.Property.SetMethod);
            }
            else if (astNodeExprSetGetLValue != null)
            {
                _placeholderStack.Push(assign.Value);
                Generate(astNodeExprSetGetLValue.SetExpression);
                if (astNodeExprSetGetLValue.SetExpression.Type != typeof(void))
                {
                    Emit(OpCodes.Pop);
                }
            }
            else
            {
                throw new NotImplementedException("Not implemented AstNodeStmAssign LValue: " +
                                                  assign.LeftValue.GetType());
            }
            //Assign.Local
        }
        protected virtual void _Generate(AstNodeExprImm item)
        {
            var itemType  = AstUtils.GetSignedType(item.Type);
            var itemValue = item.Value;

            if (itemType.IsEnum)
            {
                itemType  = itemType.GetEnumUnderlyingType();
                itemValue = AstUtils.CastType(itemValue, itemType);
            }

            if (
                itemType == typeof(int) ||
                itemType == typeof(sbyte) ||
                itemType == typeof(short) ||
                itemType == typeof(bool)
                )
            {
                var value = (int)Convert.ToInt64(itemValue);
                switch (value)
                {
                case -1:
                    Emit(OpCodes.Ldc_I4_M1);
                    break;

                case 0:
                    Emit(OpCodes.Ldc_I4_0);
                    break;

                case 1:
                    Emit(OpCodes.Ldc_I4_1);
                    break;

                case 2:
                    Emit(OpCodes.Ldc_I4_2);
                    break;

                case 3:
                    Emit(OpCodes.Ldc_I4_3);
                    break;

                case 4:
                    Emit(OpCodes.Ldc_I4_4);
                    break;

                case 5:
                    Emit(OpCodes.Ldc_I4_5);
                    break;

                case 6:
                    Emit(OpCodes.Ldc_I4_6);
                    break;

                case 7:
                    Emit(OpCodes.Ldc_I4_7);
                    break;

                case 8:
                    Emit(OpCodes.Ldc_I4_8);
                    break;

                default:
                    Emit(OpCodes.Ldc_I4, value);
                    break;
                }
            }
            else if (itemType == typeof(long) || itemType == typeof(ulong))
            {
                Emit(OpCodes.Ldc_I8, Convert.ToInt64(itemValue));
            }
            else if (itemType == typeof(IntPtr))
            {
#if false
                Emit(OpCodes.Ldc_I8, ((IntPtr)Item.Value).ToInt64());
                Emit(OpCodes.Conv_I);
#else
                if (Environment.Is64BitProcess)
                {
                    Emit(OpCodes.Ldc_I8, ((IntPtr)item.Value).ToInt64());
                    Emit(OpCodes.Conv_I);
                }
                else
                {
                    Emit(OpCodes.Ldc_I4, ((IntPtr)item.Value).ToInt32());
                    Emit(OpCodes.Conv_I);
                }
#endif
            }
            else if (itemType == typeof(float))
            {
                Emit(OpCodes.Ldc_R4, (float)item.Value);
            }
            else if (item.Value == null)
            {
                Emit(OpCodes.Ldnull);
            }
            else if (itemType == typeof(string))
            {
                Emit(OpCodes.Ldstr, (string)item.Value);
            }
            else if (itemType == typeof(Type))
            {
                Emit(OpCodes.Ldtoken, (Type)item.Value);
                Emit(OpCodes.Call, ((Func <RuntimeTypeHandle, Type>)Type.GetTypeFromHandle).Method);
                //IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
            }
            else
            {
                throw new NotImplementedException($"Can't handle immediate type {itemType}");
            }
        }