<commit_before>﻿using Pchp.Core.Dynamic;
using Pchp.Core.Utilities;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Pchp.Core.Reflection
{
    /// <summary>
    /// Collection of class fields declared in type.
    /// </summary>
    public class TypeFields
    {
        #region Fields

        /// <summary>
        /// Declared fields.
        /// </summary>
        readonly Dictionary<string, FieldInfo> _fields;

        /// <summary>
        /// Declared properties.
        /// </summary>
        readonly Dictionary<string, PropertyInfo> _properties;

        /// <summary>
        /// Declared fields in <c>__statics</c> nested class.
        /// </summary>
        readonly Dictionary<string, FieldInfo> _staticsFields;

        /// <summary>
        /// Lazily initialized function getting <c>_statics</c> in given runtime <see cref="Context"/>.
        /// </summary>
        Func<Context, object> _staticsGetter;

        #endregion

        #region Initialization

        internal TypeFields(Type type)
        {
            var tinfo = type.GetTypeInfo();

            _fields = tinfo.DeclaredFields.Where(_IsAllowedField).ToDictionary(_FieldName, StringComparer.Ordinal);
            if (_fields.Count == 0)
                _fields = null;

            var staticscontainer = tinfo.GetDeclaredNestedType("_statics");
            if (staticscontainer != null)
            {
                _staticsFields = staticscontainer.DeclaredFields.ToDictionary(_FieldName, StringComparer.Ordinal);
            }

            _properties = tinfo.DeclaredProperties.ToDictionary(_PropertyName, StringComparer.Ordinal);
            if (_properties.Count == 0)
                _properties = null;
        }

        Func<Context, object> EnsureStaticsGetter(Type type)
        {
            var getter = _staticsGetter;
            if (getter == null)
            {
                _staticsGetter = getter = CreateStaticsGetter(type);
            }

            //
            return getter;
        }

        static readonly Func<FieldInfo, bool> _isInstanceField = f => !f.IsStatic;
        static readonly Func<FieldInfo, bool> _IsAllowedField = f => ReflectionUtils.IsAllowedPhpName(f.Name) && !ReflectionUtils.IsRuntimeFields(f) && !ReflectionUtils.IsContextField(f);
        static readonly Func<FieldInfo, string> _FieldName = f => f.Name;
        static readonly Func<PropertyInfo, string> _PropertyName = p => p.Name;

        static Func<Context, object> CreateStaticsGetter(Type _statics)
        {
            Debug.Assert(_statics.Name == "_statics");
            Debug.Assert(_statics.IsNested);

            var getter = BinderHelpers.GetStatic_T_Method(_statics);    // ~ Context.GetStatics<_statics>, in closure
            // TODO: getter.CreateDelegate
            return ctx => getter.Invoke(ctx, ArrayUtils.EmptyObjects);
        }

        #endregion

        /// <summary>
        /// Gets enumeration of class instance fields excluding eventual <c>__runtime_fields</c>.
        /// </summary>
        public IEnumerable<FieldInfo> InstanceFields => (_fields != null) ? _fields.Values.Where(_isInstanceField) : Array.Empty<FieldInfo>();

        /// <summary>
        /// Enumerates all the properties in the class excluding runtime fields.
        /// </summary><commit_msg>only CLR properties without indexer reflected<commit_after>﻿using Pchp.Core.Dynamic;
using Pchp.Core.Utilities;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Pchp.Core.Reflection
{
    /// <summary>
    /// Collection of class fields declared in type.
    /// </summary>
    public class TypeFields
    {
        #region Fields

        /// <summary>
        /// Declared fields.
        /// </summary>
        readonly Dictionary<string, FieldInfo> _fields;

        /// <summary>
        /// Declared properties.
        /// </summary>
        readonly Dictionary<string, PropertyInfo> _properties;

        /// <summary>
        /// Declared fields in <c>__statics</c> nested class.
        /// </summary>
        readonly Dictionary<string, FieldInfo> _staticsFields;

        /// <summary>
        /// Lazily initialized function getting <c>_statics</c> in given runtime <see cref="Context"/>.
        /// </summary>
        Func<Context, object> _staticsGetter;

        #endregion

        #region Initialization

        internal TypeFields(Type type)
        {
            var tinfo = type.GetTypeInfo();

            _fields = tinfo.DeclaredFields.Where(_IsAllowedField).ToDictionary(_FieldName, StringComparer.Ordinal);
            if (_fields.Count == 0)
                _fields = null;

            var staticscontainer = tinfo.GetDeclaredNestedType("_statics");
            if (staticscontainer != null)
            {
                _staticsFields = staticscontainer.DeclaredFields.ToDictionary(_FieldName, StringComparer.Ordinal);
            }

            _properties = tinfo.DeclaredProperties.Where(_IsAllowedProperty).ToDictionary(_PropertyName, StringComparer.Ordinal);
            if (_properties.Count == 0)
                _properties = null;
        }

        Func<Context, object> EnsureStaticsGetter(Type type)
        {
            var getter = _staticsGetter;
            if (getter == null)
            {
                _staticsGetter = getter = CreateStaticsGetter(type);
            }

            //
            return getter;
        }

        static readonly Func<FieldInfo, bool> _isInstanceField = f => !f.IsStatic;
        static readonly Func<FieldInfo, bool> _IsAllowedField = f => ReflectionUtils.IsAllowedPhpName(f.Name) && !ReflectionUtils.IsRuntimeFields(f) && !ReflectionUtils.IsContextField(f);
        static readonly Func<FieldInfo, string> _FieldName = f => f.Name;
        static readonly Func<PropertyInfo, string> _PropertyName = p => p.Name;
        static readonly Func<PropertyInfo, bool> _IsAllowedProperty = p => ReflectionUtils.IsAllowedPhpName(p.Name) && p.GetIndexParameters().Length == 0;

        static Func<Context, object> CreateStaticsGetter(Type _statics)
        {
            Debug.Assert(_statics.Name == "_statics");
            Debug.Assert(_statics.IsNested);

            var getter = BinderHelpers.GetStatic_T_Method(_statics);    // ~ Context.GetStatics<_statics>, in closure
            // TODO: getter.CreateDelegate
            return ctx => getter.Invoke(ctx, ArrayUtils.EmptyObjects);
        }

        #endregion

        /// <summary>
        /// Gets enumeration of class instance fields excluding eventual <c>__runtime_fields</c>.
        /// </summary>
        public IEnumerable<FieldInfo> InstanceFields => (_fields != null) ? _fields.Values.Where(_isInstanceField) : Array.Empty<FieldInfo>();

        /// <summary>
        /// Enumerates all the properties in the class excluding runtime fields.
        /// </summary>
{'fraction_non_alphanumeric': 0.10869869729654014, 'fraction_numerical': 0.0007003782042302844, 'mean_word_length': 2.263254113345521, 'pattern_counts': {'":': 0, '<': 72, '<?xml version=': 0, '>': 85, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3511781', 'n_tokens_mistral': 1922, 'n_tokens_neox': 1899, 'n_words': 431}