Click here to Skip to main content
15,885,914 members
Articles / Programming Languages / ASM

Bird Programming Language: Part 3

Rate me:
Please Sign up or sign in to vote.
4.88/5 (5 votes)
1 Jan 2013GPL35 min read 29.8K   282   14  
A new general purpose language that aims to be fast, high level and simple to use.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Text;

namespace Bird
{
	public struct IdentifierFound
	{
		public IdContainer Container;
		public Identifier Identifier;

		public IdentifierFound(IdContainer Container, Identifier Identifier)
		{
			this.Container = Container;
			this.Identifier = Identifier;
		}
	}

	public struct OverloadSelectionData
	{
		public bool Specified;
		public List<Identifier> Unnamed;
		public Dictionary<string, Identifier> Named;

		public OverloadSelectionData(List<Identifier> Unnamed, Dictionary<string, Identifier> Named = null)
		{
			this.Specified = true;
			this.Unnamed = Unnamed;
			this.Named = Named;
		}

		public static OverloadSelectionData ParameterLess
		{
			get
			{
				var Ret = new OverloadSelectionData();
				Ret.Specified = true;
				Ret.Unnamed = new List<Identifier>();
				return Ret;
			}
		}
	}

	public enum GetIdMode : byte
	{
		Everywhere,
		Function,
		Container,
	}

	public struct GetIdOptions
	{
		public GetIdMode Mode;
		public OverloadSelectionData OverloadData;
		public Predicate<Identifier> Func;
		public bool EnableMessages;

		public static GetIdOptions Default
		{
			get { return new GetIdOptions() { EnableMessages = true }; }
		}
		
		public static GetIdOptions DefaultForType
		{
			get
			{
				return new GetIdOptions()
				{
					EnableMessages = true,
					Func = x => x.RealId is Type,
				};
			}
		}

		public GetIdOptions(GetIdMode Mode, bool EnableMessages = true)
		{
			this.Mode = Mode;
			this.EnableMessages = EnableMessages;
			this.OverloadData = new OverloadSelectionData();
			this.Func = null;
		}
	}

	public static class Identifiers
    {
		public static TypeOfFunction AddSelfParameter(Identifier Func, Identifier SelfType)
		{
			var Container = Func.Container;
			var FType = Func.RealId as TypeOfFunction;
			var RetCh = new Identifier[FType.Children.Length + 1];

			RetCh[0] = FType.Children[0];
			RetCh[1] = new FunctionParameter(Container, new CodeString(), SelfType);

			for (var i = 1; i < FType.Children.Length; i++)
				RetCh[i + 1] = FType.Children[i];

			return new TypeOfFunction(Container, FType.CallConv, RetCh);
		}

		public static bool IsSubtypeOrEquivalent(Identifier A, Identifier B)
		{
			return A.IsEquivalent(B) || IsSubtypeOf(A, B);
		}

		public static bool IsSubtypeOf(Identifier A, Identifier B)
		{
			if (!(A.RealId is Type)) throw new ArgumentException("A");
			if (!(B.RealId is Type)) throw new ArgumentException("B");

			var Bases = GetUnrealBases(A);
			for (var i = 0; i < Bases.Length; i++)
				if (Bases[i].Base.IsEquivalent(B)) return true;

			var AUnderlying = A.UnderlyingStructureOrRealId;
			if (AUnderlying is StructuredType)
			{
				var Structured = AUnderlying as StructuredType;
				Bases = Structured.BaseStructures;

				for (var i = 0; i < Bases.Length; i++)
					if (IsSubtypeOrEquivalent(Bases[i].Base, B)) return true;
			}

			return false;
		}

		public static StructureBase[] GetUnrealBases(Identifier Id)
		{
			if (!(Id.RealId is Type)) throw new ArgumentException("Id");

			var Type = Id.RealId as Type;
			var Global = Id.Container.GlobalContainer;

			if ((Type.Flags & IdentifierFlags.Static) != 0)
				return Global.CommonIds.EmptyBase;

			if ((Type.TypeFlags & TypeFlags.ReferenceValue) == 0)
			{
				if (Type is EnumType) return Global.CommonIds.EnumBase;
				else if (Type is TupleType) return Global.CommonIds.TupleBase;
				else return Global.CommonIds.ValueTypeBase;
			}
			else
			{
				if (Type is RefArrayType) return Global.CommonIds.ArrayBase;
				else return Global.CommonIds.EmptyBase;
			}
		}

		public static Identifier GetBoxClass(Identifier Id)
		{
			var Type = Id.RealId as Type;
			if ((Type.TypeFlags & TypeFlags.ReferenceValue) != 0)
				throw new ArgumentException("Id");

			string Name;
			if (Type is EnumType) Name = "System.Enum";
			else if (Type is TupleType) Name = "System.Tuple";
			else Name = "System.ValueType";

			var State = Id.Container.State;
			return Identifiers.GetByFullNameFast<ClassType>(State, Name, false);
		}

        public static string GetFullName(Identifier Id, bool Overload = false)
        {
            var Lang = Id.Container.State.Language;
            if (Lang.FullNameGenerator == null) return null;
            return Lang.FullNameGenerator.GetFullName(Id, Overload);
        }

        public static bool AreParametersSame(Identifier A, Identifier B)
        {
            var FuncA = A.RealId as Function;
            var FuncB = B.RealId as Function;
            var AType = FuncA.Children[0].RealId as TypeOfFunction;
            var BType = FuncB.Children[0].RealId as TypeOfFunction;

            var Ch = AType.Children;
            if (Ch.Length != BType.Children.Length)
                return false;

            for (var i = 1; i < Ch.Length; i++)
            {
                if (!Ch[i].TypeOfSelf.IsEquivalent(BType.Children[i].TypeOfSelf))
                    return false;
            }

            return true;
        }

		public static bool IsScalarOrVectorNumber(Identifier Id)
		{
			return ProcessTuple(Id, x => x.RealId is NumberType);
		}

		public static bool ProcessTuple(Identifier Id, Predicate<Identifier> Func)
		{
			var Tuple = Id.RealId as TupleType;
			if (Tuple != null)
				return Tuple.TrueForAllMembers(x => Func(x.Children[0]));

			return Func(Id);
		}

		public static void MoveIdentifier(Identifier Id, IdContainer NewContainer)
		{
			if (!Id.Container.IsSubContainerOf(NewContainer) || NewContainer.FunctionScope == null)
				throw new ArgumentException();

			Id.Container.IdentifierList.Remove(Id);
			Id.Container = NewContainer;
			NewContainer.IdentifierList.Add(Id);
		}

		public static bool IsNullable(Identifier Id)
		{
			var Type = Id.UnderlyingClassOrRealId as Type;
			if (!(Type is Type)) Type = Id.TypeOfSelf.UnderlyingClassOrRealId as Type;
			return (Type.TypeFlags & TypeFlags.ReferenceValue) != 0;
		}

		public static bool IsNullableType(Identifier Id)
		{
			var Type = Id.UnderlyingClassOrRealId as Type;
			return Type != null && (Type.TypeFlags & TypeFlags.ReferenceValue) != 0;
		}

		public static bool IsBoxing(Identifier From, Identifier To)
		{
			var TFrom = From.RealId as Type;
			if ((TFrom.TypeFlags & TypeFlags.ReferenceValue) != 0)
				return false;

			var RealOrUnderlying = From.UnderlyingStructureOrRealId;
			if (!(RealOrUnderlying is StructType || TFrom is EnumType))
				return false;

			var TTo = To.RealId as Type;
			return TTo is ObjectType || TTo.AssemblyName == "_System_ValueType" ||
				(TFrom is EnumType && TTo.AssemblyName == "_System_Enum") ||
				(TFrom is TupleType && TTo.AssemblyName == "_System_Tuple");
		}

		public static void LinkTypes(BuiltinType Type1, StructuredType Type2)
		{
			Type1.UnderlyingType = Type2;
			Type2.RealId = Type1;
		}

		public static Identifier CreateTupleMember(IdContainer Container, Identifier Type)
		{
			var Var = new MemberVariable(Container, new CodeString(), Type);
			Var.Access = Type.Access;
			return Var;
		}

		public static TupleType CreateTupleFromTypes(IdContainer Container, List<Identifier> Types)
		{
			var Members = new List<Identifier>();
			for (var i = 0; i < Types.Count; i++)
				Members.Add(CreateTupleMember(Container, Types[i]));

			return new TupleType(Container, Members);
		}

		public static void RemoveOutside(IdContainer Container, List<Identifier> List)
		{
			for (var i = 0; i < List.Count; i++)
			{
				var C = List[i].Container;
				if (C != Container && !Container.IsSubContainerOf(C))
				{
					List.RemoveAt(i);
					i--;
				}
			}
		}

		public static void RemoveOutside(IdContainer Container, AutoAllocatedList<Identifier> List)
		{
			if (List.List != null)
				RemoveOutside(Container, List.List);
		}

		public static List<IdentifierFound> Search(IdContainer Container, List<Identifier> List, string Name,
			Predicate<Identifier> Func = null)
		{
			var Out = new List<IdentifierFound>();
			Search(Container, List, Name, Out, Func);
			return Out;
		}

		public static List<IdentifierFound> Search(IdContainer Container, AutoAllocatedList<Identifier> List,
			string Name, Predicate<Identifier> Func = null)
		{
			var Out = new List<IdentifierFound>();
			if (List.List != null)
				Search(Container, List.List, Name, Out, Func);

			return Out;
		}

		static bool Contains(List<IdentifierFound> List, Identifier Id)
		{
			for (var i = 0; i < List.Count; i++)
			{
				if (List[i].Identifier == Id)
					return true;
			}

			return false;
		}

		public static bool Search(IdContainer Container, List<Identifier> List, string Name,
			List<IdentifierFound> Out, Predicate<Identifier> Func = null) 
		{
			var RetValue = false;

			if (Name == null)
			{
				for (var i = 0; i < List.Count; i++)
				{
					var Item = List[i];
					if (Item != null && (Func == null || Func(Item)) && !Contains(Out, Item))
					{
						Out.Add(new IdentifierFound(Container, Item));
						RetValue = true;
					}
				}
			}
			else
			{
				if (Func == null)
				{
					for (var i = 0; i < List.Count; i++)
					{
						var Item = List[i];
						if (Item != null && Item.Name.IsValid && Item.Name.IsEqual(Name) && !Contains(Out, Item))
						{
							Out.Add(new IdentifierFound(Container, Item));
							RetValue = true;
						}
					}
				}
				else
				{
					for (var i = 0; i < List.Count; i++)
					{
						var Item = List[i];
						if (Item != null && Item.Name.IsValid && Item.Name.IsEqual(Name) && !Contains(Out, Item))
						{
							if (Func(Item)) Out.Add(new IdentifierFound(Container, Item));
							RetValue = true;
						}
					}
				}
			}

			return RetValue;
		}

		public static bool Search(IdContainer Container, AutoAllocatedList<Identifier> List, string Name,
			List<IdentifierFound> Out, Predicate<Identifier> Func = null)
		{
			if (List.List != null)
				return Search(Container, List.List, Name, Out, Func);

			return false;
		}

		public static T GetByFullNameFast<T>(CompilerState State, string Name, bool EnableMessages = true)
			where T : Identifier
		{
			return GetByFullNameFast<T>(State.GlobalContainer, Name, EnableMessages);
		}

		public static T GetByFullNameFast<T>(GlobalContainer Global, string Name, bool EnableMessages = true)
			where T : Identifier
		{
			var Ret = GetByFullNameFast(Global, Name, EnableMessages);
			if (Ret == null) return null;

			if (!(Ret is T))
			{
				if (EnableMessages)
				{
					var Messages = Global.State.Messages;
					Messages.Add(MessageId.UnknownId, new CodeString(Name));
				}

				return null;
			}

			return Ret as T;
		}

		public static Identifier GetByFullNameFast(CompilerState State, string Name, bool EnableMessages = true)
		{
			return GetByFullNameFast(State.GlobalContainer, Name, EnableMessages);
		}

		public static Identifier GetByFullNameFast(GlobalContainer Global, string Name, bool EnableMessages = true)
		{
			lock (Global.FastIds)
			{
				Identifier Id;
				if (Global.FastIds.TryGetValue(Name, out Id))
					return Id;

				var Options = new GetIdOptions() { EnableMessages = EnableMessages };
				var Ret = GetFromMembers(Global.GlobalNamespace, new CodeString(Name), Options);
				if (Ret == null) return null;

				Global.FastIds.Add(Name, Ret);
				return Ret;
			}
		}

		public static Identifier GetByFullName(CompilerState State, string Name)
		{
			return GetFromMembers(State.GlobalContainer.GlobalNamespace,
				new CodeString(Name), GetIdOptions.Default);
		}

		public static Identifier GetByFullName(GlobalContainer Global, string Name)
		{
			return GetFromMembers(Global.GlobalNamespace, new CodeString(Name), GetIdOptions.Default);
		}

		public static Identifier GetByFullName(GlobalContainer Global, CodeString Name)
		{
			return GetFromMembers(Global.GlobalNamespace, Name, GetIdOptions.Default);
		}

		public static Identifier GetByFullName(GlobalContainer Global, CodeString Name, GetIdOptions Options)
		{
			return GetFromMembers(Global.GlobalNamespace, Name, Options);
		}

		public static Identifier GetFromMembers(Identifier CurrentId, CodeString Name, GetIdOptions Options)
		{
			var Container = CurrentId.Container;
			var State = Container.State;
			var Splitted = Name.Split('.');

			var OptCopy = Options;
			OptCopy.Func = null;

			for (var i = 0; i < Splitted.Count; i++)
			{
				var LOps = i < Splitted.Count - 1 ? OptCopy : Options;
				CurrentId = GetMember(State, CurrentId, Splitted[i], LOps);
				if (CurrentId == null) return null;
			}

			return CurrentId;
		}

		public static Identifier GetFromMembers(IdContainer Container, CodeString Name, GetIdOptions Options)
		{
			var State = Container.State;
			var Splitted = Name.Split('.');

			var OptCopy = Options;
			OptCopy.OverloadData.Specified = false;
			OptCopy.Func = null;

			var IdList = Container.GetIdentifier(Splitted[0].ToString(), OptCopy.Mode);
			var CurrentId = SelectIdentifier(State, IdList, Splitted[0], OptCopy);
			if (CurrentId == null) return null;

			for (var i = 1; i < Splitted.Count; i++)
			{
				var LOps = i < Splitted.Count - 1 ? OptCopy : Options;
				CurrentId = GetMember(State, CurrentId, Splitted[i], LOps);
				if (CurrentId == null) return null;
			}

			return CurrentId;
		}

		public static bool IsDefined(List<Identifier> List, string Name) 
		{
			if (Name == null)
			{
				return List.Count > 0;
			}
			else
			{
				for (var i = 0; i < List.Count; i++)
				{
					var Id = List[i];
					if (Id.Name.IsValid && Id.Name.IsEqual(Name))
						return true;
				}
			}

			return false;
		}

		public static bool IsDefined(AutoAllocatedList<Identifier> List, string Name)
		{
			return List.List == null ? false : IsDefined(List.List, Name);
		}

		public static bool IsMoreRestrictive(IdentifierAccess First, IdentifierAccess Second)
		{
			if (First == IdentifierAccess.Unknown || Second == IdentifierAccess.Unknown)
				throw new Exception("EROR");

			if (First == IdentifierAccess.Private && Second == IdentifierAccess.Internal) return false;
			if (First == IdentifierAccess.Internal && Second == IdentifierAccess.Private) return false;

			if (((int)First & 3) > ((int)Second & 3)) return true;
			if ((First & IdentifierAccess.Internal) != 0 && ((Second & IdentifierAccess.Internal) == 0))
				return true;

			return false;
		}

		public static bool IsLessRestrictive(IdentifierAccess First, IdentifierAccess Second)
		{
			if (First == IdentifierAccess.Unknown || Second == IdentifierAccess.Unknown)
				throw new Exception("EROR");

			if (First == IdentifierAccess.Private && Second == IdentifierAccess.Internal) return false;
			if (First == IdentifierAccess.Internal && Second == IdentifierAccess.Private) return false;

			if (((int)First & 3) < ((int)Second & 3)) return true;
			if ((First & IdentifierAccess.Internal) == 0 && ((Second & IdentifierAccess.Internal) != 0))
				return true;

			return false;
		}

		public static IdentifierAccess IdAccessIntersect(Identifier[] Ids)
		{
			var Access = Ids[0].Access;
			for (var i = 1; i < Ids.Length; i++)
				Access = Identifiers.IdAccessIntersect(Access, Ids[i].Access);

			return Access;
		}

		public static IdentifierAccess IdAccessIntersect(List<Identifier> Ids)
		{
			var Access = Ids[0].Access;
			for (var i = 1; i < Ids.Count; i++)
				Access = Identifiers.IdAccessIntersect(Access, Ids[i].Access);

			return Access;
		}

		public static IdentifierAccess IdAccessIntersect(AutoAllocatedList<Identifier> Ids)
		{
			if (Ids.List != null) return IdAccessIntersect(Ids.List);
			else return IdentifierAccess.Public;
		}

		public static IdentifierAccess IdAccessIntersect(IdentifierAccess First, IdentifierAccess Second)
		{
			var Ret = Second;
			if (((int)First & 3) > ((int)Second & 3))
				Ret = First;

			if (((int)First & 3) != (int)IdentifierAccess.Private)
			{
				if ((First & IdentifierAccess.Internal) != 0 || (Second & IdentifierAccess.Internal) != 0)
					Ret |= IdentifierAccess.Internal;
			}

			return Ret;
		}

		public static IdentifierAccess GetRealAccess(IdContainer Container, Identifier Id)
		{
			var Current = Id.Container;
			var Access = Id.Access;

			while (Current != Container)
			{
				var TypeScope = Current as TypeScope;
				if (TypeScope != null)
				{
					var ScopeId = TypeScope.Identifier;
					Access = IdAccessIntersect(Access, ScopeId.Access);
				}

				if ((Current = Current.Parent) == null)
					throw new ApplicationException();
			}

			return Access;
		}

		public static bool IsLessAccessable(Identifier Id, Identifier Id2)
		{
			var Container = Id.Container.GetCommonContainer(Id2.Container);
			if (Container == null) throw new ApplicationException();

			var Access = GetRealAccess(Container, Id);
			var Access2 = GetRealAccess(Container, Id2);
			return IsMoreRestrictive(Access, Access2);
		}

		public static Type GetType(Identifier Id)
		{
			var Var = Id.RealId as Variable;
			var Type = Var != null ? Var.TypeOfSelf : Id;
            return Type.RealId as Type;
		}

		public static bool ContainsMember(Identifier Id, string Name, Predicate<Identifier> Func = null)
		{
			return SearchMember(null, Id, Name, Func).Count > 0;
		}

		public static List<IdentifierFound> SearchBaseMember(IdContainer Container, 
			Identifier Id, string Name, Predicate<Identifier> Func = null)
		{
			var List = new List<IdentifierFound>();
			SearchBaseMember(Container, Id, Name, List, Func);
			return List;
		}

		public static bool SearchBaseMember(IdContainer Container, Identifier Id, string Name,
			List<IdentifierFound> Out, Predicate<Identifier> Func = null)
		{
			Id = Id.UnderlyingStructureOrRealId;
			if (!(Id.RealId is Type)) throw new ArgumentException("Id");

			var Global = Id.Container.GlobalContainer;
			if ((Global.Flags & GlobalContainerFlags.StructureMembersParsed) == 0)
				throw new InvalidOperationException();

			var RetValue = false;
			if (Id.RealId is StructuredType)
			{
				var Structure = Id.RealId as StructuredType;
				for (var i = 0; i < Structure.BaseStructures.Length; i++)
				{
					var Base = Structure.BaseStructures[0].Base;
					if (SearchMember(Container, Base, Name, Out, Func))
						RetValue = true;
				}
			}

			if (!RetValue)
			{
				var UnrealBases = GetUnrealBases(Id);
				for (var i = 0; i < UnrealBases.Length; i++)
				{
					var Base = UnrealBases[0].Base;
					if (SearchMember(Container, Base, Name, Out, Func))
						RetValue = true;
				}
			}

			return RetValue;
		}

		public static List<IdentifierFound> SearchMember(IdContainer Container, Identifier Id, 
			string Name, Predicate<Identifier> Func = null)
		{
			var List = new List<IdentifierFound>();
			SearchMember(Container, Id, Name, List, Func);
			return List;
		}

		public static bool SearchMember(IdContainer Container, Identifier Id, string Name, 
			List<IdentifierFound> Out, Predicate<Identifier> Func = null)
		{
			Id = Id.UnderlyingStructureOrRealId;
			if (!(Id.RealId is Type || Id.RealId is Namespace || Id.RealId is Property))
				throw new ArgumentException("Id");

			var RetValue = false;
			if (Id.RealId is TupleType && new StringSlice(Name).IsNumber)
			{
				var Tuple = Id.RealId as TupleType;
				var Members = Tuple.StructuredScope.IdentifierList;

				var i = Convert.ToInt32(Name);
				if (i >= 0 && i < Members.Count)
				{
					var Item = Members[i];
					if (Item != null && (Func == null || Func(Item)))
					{
						Out.Add(new IdentifierFound(Container, Members[i]));
						RetValue = true;
					}
				}
			}

			if (!RetValue && Id.HasScopes)
			{
				foreach (var e in Id.EnumScopes)
				{
					if (Search(Container, e.IdentifierList, Name, Out, Func))
						RetValue = true;
				}
			}

			var Global = Id.Container.GlobalContainer;
			if ((Global.Flags & GlobalContainerFlags.StructureMembersParsed) != 0)
			{
				var Underlying = Id.UnderlyingStructureOrRealId;
				if (!RetValue && Underlying is StructuredType)
				{
					var Structure = Underlying as StructuredType;
					for (var i = 0; i < Structure.BaseStructures.Length; i++)
					{
						var Base = Structure.BaseStructures[0].Base;
						if (SearchMember(Container, Base, Name, Out, Func))
							RetValue = true;
					}
				}

				if (!RetValue && Id.RealId is Type)
				{
					var UnrealBases = GetUnrealBases(Id);
					for (var i = 0; i < UnrealBases.Length; i++)
					{
						var Base = UnrealBases[0].Base;
						if (SearchMember(Container, Base, Name, Out, Func))
							RetValue = true;
					}
				}
			}

			return RetValue;
		}

		public static Identifier GetMember(CompilerState State, Identifier Id, 
			string Right, CodeString Code)
		{
			var List = SearchMember(null, Id, Right);
			return SelectIdentifier(State, List, Code);
		}

		public static Identifier GetMember(CompilerState State, Identifier Id, 
			string Right, CodeString Code, GetIdOptions Options)
		{
			var List = SearchMember(null, Id, Right, Options.Func);
			return SelectIdentifier(State, List, Code, Options);
		}

		public static Identifier GetMember(CompilerState State, Identifier Id, 
			CodeString Right, GetIdOptions Options)
		{
			var List = SearchMember(null, Id, Right.ToString(), Options.Func);
			return SelectIdentifier(State, List, Right, Options);
		}

		public static Identifier GetMember(CompilerState State, Identifier Id, 
			string Right, GetIdOptions Options)
		{
			var List = SearchMember(null, Id, Right, Options.Func);
			return SelectIdentifier(State, List, new CodeString(Right), Options);
		}

		public static Identifier GetMember(CompilerState State, Identifier Id, CodeString Right)
		{
			var List = SearchMember(null, Id, Right.ToString());
			return SelectIdentifier(State, List, Right, GetIdOptions.Default);
		}

		public static Identifier GetMember(IdContainer Container, CodeString Left, 
			CodeString Right, GetIdOptions Options)
		{
			var LeftOptions = Options;
			LeftOptions.Func = x => x.HasScopes;

			var Id = Identifiers.Recognize(Container, Left, LeftOptions);
			if (Id == null) return null;
			
			return GetMember(Container.State, Id, Right, Options);
		}

		public static Identifier GetMember(IdContainer Container, CodeString Left, CodeString Right)
		{
			return GetMember(Container, Left, Right, GetIdOptions.Default);
		}

		static int GetFunctionValue(Function Func, OverloadSelectionData Data)
		{
			var State = Func.Container.State;
			var FuncType = Func.TypeOfSelf.RealId as TypeOfFunction;
			var FuncCh = FuncType.Children;
			var FuncParamCount = FuncCh.Length - 1;
			var Specified = new bool[FuncParamCount];

			var Value = 0;
			if (Data.Unnamed != null)
			{
				var Processed = false;
                if ((State.Language.Flags & LangaugeFlags.ConvertParametersToTuple) != 0
					&& Data.Unnamed.Count > 1 && Data.Named == null && FuncParamCount == 1)
				{
					var Tuple = FuncCh[1].TypeOfSelf.RealId as TupleType;
					if (Tuple != null)
					{
						var Members = Tuple.StructuredScope.IdentifierList;
						var NewValue = Members.Count == Data.Unnamed.Count ? 4 : 0;

						if (NewValue == 4)
						{
							for (var i = 0; i < Data.Unnamed.Count; i++)
							{
								var Type = Data.Unnamed[i].RealId as Type;
								var Res = Type.CanConvert(Members[i].TypeOfSelf);
								if (Res == TypeConversion.Convertable)
								{
									if (NewValue > 1) NewValue = 1;
								}
								else if (Res == TypeConversion.Nonconvertable)
								{
									NewValue = 0;
									break;
								}
							}

							if (NewValue > 0)
							{
								Value += NewValue;
								Processed = true;
								Specified[0] = true;
							}
						}
					}
				}

				if (!Processed)
				{
					var LastParam = FuncCh[FuncCh.Length - 1] as FunctionParameter;
					
					for (var i = 0; i < Data.Unnamed.Count; i++)
					{
						if (LastParam != null && (LastParam.ParamFlags & ParameterFlags.ParamArray) != 0)
						{
							if (i == FuncParamCount - 1)
							{
								var PValue = GetParamValue(Data.Unnamed[i], LastParam.Children[0]);
								if (PValue > 0)
								{
									Value += PValue;
									Specified[FuncParamCount - 1] = true;
									break;
								}
							}

							if (i >= FuncParamCount - 1)
							{
								var Type = GetParamArrayBaseType(LastParam.Children[0]);
								Value += GetParamValue(Data.Unnamed[i], Type);
								Specified[FuncParamCount - 1] = true;
								continue;
							}
						}
						else
						{
                            if (i >= FuncParamCount)
                            {
                                Value = 0;
                                break;
                            }
						}

						var Param = FuncCh[i + 1] as FunctionParameter;
						Value += GetParamValue(Data.Unnamed[i], Param.Children[0]);
						Specified[i] = true;
					}
				}
			}

			if (Data.Named != null)
			{
				foreach (var e in Data.Named)
				{
					var Param = FuncType.GetParameter(e.Key);
					if (Param == null) continue;

					var Index = FuncType.GetChildIndex(Param);
					if (Specified[Index]) continue;

					Value += GetParamValue(e.Value, Param.Children[0]);
					Specified[Index] = true;
				}
			}

			for (var i = 0; i < FuncParamCount; i++)
			{
				var Param = FuncCh[i + 1] as FunctionParameter;
				if (!Specified[i] && Param.ConstInitValue == null) Value -= 3;
			}

			return Value;
		}

		public static Identifier GetParamArrayBaseType(Identifier Type)
		{
			if (Type.RealId is ArrayType || Type.RealId is PointerType)
			{
				return Type.Children[0];
			}
			else if (Type.RealId is PointerAndLength)
			{
				var PAndL = Type.RealId as PointerAndLength;
				return PAndL.Child;
			}
			else
			{
				throw new ApplicationException();
			}
		}

		private static int GetParamValue(Identifier From, Identifier To)
		{
			if (From.IsEquivalent(To))
			{
				return 4;
			}
			else
			{
				var RFrom = From.RealId;
				var RTo = To.RealId;

				if (RFrom is ArrayType && RTo is ArrayType && RFrom.Children[0].RealId is AutomaticType)
					return 3;

				var Res = RFrom.CanConvert(RTo);
				if (Res == TypeConversion.Automatic) return 2;
				else if (Res == TypeConversion.Convertable) return 1;
				else if (Res == TypeConversion.Nonconvertable) return 0;
				else throw new ApplicationException();
			}
		}

		private static int GetIdentifierPriority(Identifier Id)
		{
			Id = Id.RealId;
			if (Id is Namespace) return 0;
			if (Id is Type) return 1;
			return 2;
		}

		static void Exclude(List<IdentifierFound> List, int[] Priorities)
		{
			var MaxPriority = int.MinValue;
			for (var i = 0; i < List.Count; i++)
				if (MaxPriority < Priorities[i]) MaxPriority = Priorities[i];

			var j = 0;
			for (var i = 0; i < Priorities.Length; i++)
			{
				if (Priorities[i] < MaxPriority)
				{
					List.RemoveAt(j);
					continue;
				}

				j++;
			}
		}

		static void ExcludeParamArrays(List<IdentifierFound> List)
		{
			var Priorities = new int[List.Count];
			for (var i = 0; i < List.Count; i++)
			{
				if (List[i].Identifier is Function)
				{
					var FuncType = List[i].Identifier.Children[0] as TypeOfFunction;
					var LastParam = FuncType.Children[FuncType.Children.Length - 1] as FunctionParameter;
					if (LastParam != null && (LastParam.ParamFlags & ParameterFlags.ParamArray) != 0)
					{
						Priorities[i] = 0;
						continue;
					}
				}

				Priorities[i] = 1;
			}

			Exclude(List, Priorities);
		}

		static void ExcludeBasedOnIdPriority(List<IdentifierFound> List)
		{
			var Priorities = new int[List.Count];
			for (var i = 0; i < List.Count; i++)
				Priorities[i] = GetIdentifierPriority(List[i].Identifier);

			Exclude(List, Priorities);
		}

		static void ExcludeBasedOnParamMatching(List<IdentifierFound> List, OverloadSelectionData Data)
		{
			if (Data.Specified)
			{
				var Priorities = new int[List.Count];
				for (var i = 0; i < List.Count; i++)
				{
					var Func = List[i].Identifier.RealId as Function;
					if (Func == null) Priorities[i] = -1;
					else Priorities[i] = GetFunctionValue(Func, Data);
				}

				Exclude(List, Priorities);
			}
		}

		static void ExcludeBasedOnContainer(List<IdentifierFound> List)
		{
			for (var i = 0; i < List.Count; i++)
			{
				if (List[i].Container == null)
					continue;

				var Remove = false;
				for (var j = 0; j < List.Count; j++)
				{
					var JContainer = List[j].Container;
					if (JContainer != null && JContainer.IsSubContainerOf(List[i].Container))
					{
						Remove = true;
						break;
					}
				}

				if (Remove)
				{
					List.RemoveAt(i);
					i--;
				}
			}
		}

		static Identifier SelectIdentifierHelper(CompilerState State, List<IdentifierFound> List,
			CodeString Code, OverloadSelectionData Data, bool EnableMessages)
		{
			if (List.Count == 0) throw new ApplicationException();
			else if (List.Count == 1) return List[0].Identifier;

			var NewList = List.ToList();
			ExcludeBasedOnIdPriority(NewList);
			ExcludeBasedOnParamMatching(NewList, Data);
			ExcludeParamArrays(NewList);
			ExcludeBasedOnContainer(NewList);

			if (NewList.Count > 1)
			{
				if (EnableMessages)
					State.Messages.Add(MessageId.AmbiguousReference, Code);

				return null;
			}

			return NewList[0].Identifier;
		}

		public static Identifier SelectIdentifier(CompilerState State, List<IdentifierFound> List,
			CodeString Code, GetIdOptions Options)
		{
			if (List.Count == 0)
			{
				if (Options.EnableMessages)
					State.Messages.Add(MessageId.UnknownId, Code);

				return null;
			}

			return SelectIdentifierHelper(State, List, Code, Options.OverloadData, Options.EnableMessages);
		}

		public static Identifier SelectIdentifier(CompilerState State, List<IdentifierFound> List, CodeString Code)
		{
			return SelectIdentifier(State, List, Code, GetIdOptions.Default);
		}

		static bool CanAccessPrivate(IdContainer Container, Identifier Id)
		{
			var RealContainer = Id.Container.RealContainer;
			while (RealContainer != Container)
			{
				Container = Container.Parent;
				if (Container == null) return false;
			}

			return true;
		}

		static bool CanAccessProtected(IdContainer Container, Identifier Id)
		{
			var TypeScope = Container.StructuredScope;
			if (TypeScope != null) return CanAccessProtected(TypeScope, Id);
			
			return false;
		}

		static bool CanAccessProtected(StructuredScope Scope, Identifier Id)
		{
			if (Scope.IdentifierList.Contains(Id))
				return true;

			var Type = Scope.StructuredType;
			for (var i = 0; i < Type.BaseStructures.Length; i++)
			{
				var Base = Type.BaseStructures[i].Base;
				var SBase = Base.UnderlyingStructureOrRealId as StructuredType;

				if (CanAccessProtected(SBase.StructuredScope, Id))
					return true;
			}

			return false;
		}

		public static bool VerifyAccess(IdContainer Container, Identifier Id, CodeString Str, bool EnableMessages = true)
		{
			var State = Container.State;
			if (Id.Access == IdentifierAccess.Public || Id.Access == IdentifierAccess.Unknown)
				return true;

			if ((Id.Access & IdentifierAccess.Internal) != 0)
			{
				if (!Id.Container.IsScopeOfAssembly())
				{
					if (EnableMessages)
						State.Messages.Add(MessageId.CantAccessInternal, Str);

					return false;
				}
			}

			if ((Id.Access & IdentifierAccess.Protected) != 0)
			{
				if (!CanAccessProtected(Container, Id))
				{
					if (EnableMessages)
						State.Messages.Add(MessageId.CantAccessProtected, Str);

					return false;
				}
			}

			if ((Id.Access & IdentifierAccess.Private) != 0)
			{
				if (!Id.Container.IsScopeOfAssembly())
				{
					if (EnableMessages)
						State.Messages.Add(MessageId.PrivateInOtherLib, Str);

					return false;
				}
				else if (!CanAccessPrivate(Container, Id))
				{
					if (EnableMessages)
						State.Messages.Add(MessageId.CantAccessPrivate, Str);

					return false;
				}
			}

			return true;
		}

		public static Identifier Recognize(IdContainer Container, CodeString Code)
		{
			var Rec = Container.State.Language.IdRecognizers;
			return Recognize(Container, Code, GetIdOptions.Default, Rec);
		}

		public static Identifier Recognize(IdContainer Container, CodeString Code, GetIdOptions Options)
		{
			var Rec = Container.State.Language.IdRecognizers;
			return Recognize(Container, Code, Options, Rec);
		}

		public static Identifier Recognize(IdContainer Container, CodeString Code, 
			GetIdOptions Options, IList<IIdRecognizer> Recognizers)
		{
			for (var i = 0; i < Recognizers.Count; i++)
			{
				Identifier Out = null;
				var Res = Recognizers[i].Recognize(Container, Code, Options, ref Out);
				if (Res != SimpleRecResult.Unknown)
				{
					if (Res == SimpleRecResult.Succeeded)
					{
						if (Out == null)
							throw new ApplicationException("Recognized identifier name cannot be null");

						return Out;
					}
					else
					{
						return null;
					}
				}
			}

			if (Options.EnableMessages)
				Container.State.Messages.Add(MessageId.UnknownId, Code);

			return null;
		}
	}

	public enum DeclaredIdType : byte
	{
		Unknown,
		Alias,
		Class,
		Struct,
		Enum,
		Flag,
		Function,
		Constructor,
		Destructor,
		Variable,
		Constant,
		Property,
		Namespace,
	}

	public enum UndeclaredIdType : byte
	{
		Unknown,
		Pointer,
		Reference,
		Tuple,
		Function,
		NonrefArrayType,
		RefArrayType,
        PointerAndLength,
		NonstaticFunctionType,

		SByte,
		Int16,
		Int32,
		Int64,

		Byte,
		UInt16,
		UInt32,
		UInt64,

        IntPtr,
        UIntPtr,

		Single,
		Double,

		Boolean,
		Object,
		String,
		Char,

		Void,
		Type,
		Auto,
		Null,
		Namespace,
	}

	[Flags]
	public enum IdentifierAccess : byte
	{
		Public = 0,
		Protected = 1,
		Private = 2,
		Internal = 4,
		InternalProtected = Internal | Protected,
		Unknown = Internal | Private,
	}

	[Flags]
	public enum IdentifierFlags : ushort
	{
		None = 0,
		Virtual = 1,
		Override = 2,
		Abstract = 4,
		Sealed = 8,
		Static = 16,
		Extern = 32,
		ReadOnly = 64,
		SpecialName = 128,
        HideBaseId = 256,
		All = Virtual | Override | Abstract | Sealed | Static | Extern | ReadOnly | SpecialName,

		// AssemblyDesc: 16384, 32768
	}

	public abstract class Identifier
	{
		public DataList Data = new DataList();
		public IdContainer Container;
		public CodeString Name;
		public CodeString Declaration;
		public Identifier[] Children;
        public Identifier RealId;
        public Identifier OverriddenId;

		public IdentifierAccess Access = IdentifierAccess.Private;
		public IdentifierFlags Flags = IdentifierFlags.None;
		public UndeclaredIdType UndeclaredIdType = UndeclaredIdType.Unknown;
		public DeclaredIdType DeclaredIdType = DeclaredIdType.Unknown;

		public bool Used = false;
		public int ReferenceIndex = -1;
		public long DescPosition = -1;
		public int LocalIndex = -1;
        public abstract Identifier TypeOfSelf { get; }

		public Identifier UnderlyingClassOrSelf
		{
			get
			{
				var BuiltinType = this as BuiltinType;
				if (BuiltinType != null && BuiltinType.UnderlyingType is ClassType)
					return BuiltinType.UnderlyingType;

				return this;
			}
		}

		public Identifier UnderlyingClassOrRealId
		{
			get
			{
				var BuiltinType = RealId as BuiltinType;
				if (BuiltinType != null && BuiltinType.UnderlyingType is ClassType)
					return BuiltinType.UnderlyingType;

				return RealId;
			}
		}

		public Identifier UnderlyingStructureOrSelf
		{
			get
			{
				var BuiltinType = this as BuiltinType;
				if (BuiltinType != null && BuiltinType.UnderlyingType != null)
					return BuiltinType.UnderlyingType;

				return this;
			}
		}

		public Identifier UnderlyingStructureOrRealId
		{
			get
			{
				var BuiltinType = RealId as BuiltinType;
				if (BuiltinType != null && BuiltinType.UnderlyingType != null)
					return BuiltinType.UnderlyingType;

				return RealId;
			}
		}

		public virtual TypeConversion CanConvert(Identifier To)
		{
			if (RealId != this) return RealId.CanConvert(To);
			else throw new InvalidOperationException();
		}

		public virtual bool IsEquivalent(Identifier Id)
		{
			return Id == this || RealId == Id || Id.RealId == this;
		}

		public virtual bool IsInstanceIdentifier
		{
			get { return (Flags & IdentifierFlags.Static) == 0 && Container.RealContainer is StructuredScope; }
		}

		public int GetChildIndex(Identifier Id)
		{
			if (Children != null)
			{
				for (var i = 0; i < Children.Length; i++)
					if (Children[i] == Id) return i;
			}

			return -1;
		}

		public void GenerateName()
		{
			var Name = Container.State.GenerateName(this);
			this.Name = new CodeString(Name);
		}

		public virtual void CalculateAccess()
		{
			if (Children == null || Children.Length == 0)
				Access = Container.DefaultAccess;
			else Access = Identifiers.IdAccessIntersect(Children);
		}

		public virtual void Update()
		{
		}

		public virtual bool HasScopes
		{
			get
			{
				if (RealId == this) return false;
				else return RealId.HasScopes;
			}
		}

		public virtual IEnumerable<ScopeNode> EnumScopes
		{
			get
			{
				if (RealId == this) return null;
				else return RealId.EnumScopes;
			}
		}

		string _AssemblyName = null;
		string _AssemblyNameWithoutDecorations = null;
		public string AssemblyName
		{
			get
			{
				if (_AssemblyName == null)
					_AssemblyName = CalculateAssemblyName(true);

				return _AssemblyName;
			}

			set
			{
				Flags |= IdentifierFlags.SpecialName;
				_AssemblyName = value;
			}
		}

		public string AssemblyNameWithoutDecorations
		{
			get
			{
				if ((Flags & IdentifierFlags.SpecialName) != 0) 
					return _AssemblyName;
				else if (_AssemblyNameWithoutDecorations != null)
					return _AssemblyNameWithoutDecorations;

				_AssemblyNameWithoutDecorations = CalculateAssemblyName(false);
				return _AssemblyNameWithoutDecorations;
			}
		}

		public void SetUsed()
		{
			Used = true;

			if (Children != null)
			{
				for (var i = 0; i < Children.Length; i++)
					if (Children[i] != null) Children[i].SetUsed();
			}
		}

		public virtual bool CalculateLayout()
		{
			if (Children != null)
			{
				for (var i = 0; i < Children.Length; i++)
				{
					if (Children[i].DeclaredIdType == DeclaredIdType.Unknown)
						if (!Children[i].CalculateLayout()) return false;
				}
			}

			return true;
		}

		protected virtual string CalculateAssemblyName(bool Decorations)
		{
			return Container.AssemblyName + "_" + Name.ToString();
		}

		public Identifier(IdContainer Container, CodeString Name)
		{
			if (Container == null)
				throw new ArgumentNullException("Container");

			this.Name = Name;
			this.Declaration = Name;
			this.Container = Container;
			this.Access = Container.DefaultAccess;
			this.RealId = this;
		}

		public virtual void GetAssembly(CodeGenerator CG, GetAssemblyMode Mode)
		{
		}

		public virtual void GetGlobalPointers(List<string> Out)
		{
		}
	}

	public class IdentifierAlias : Identifier
	{
		public IdentifierAlias(IdContainer Container, CodeString Name, Identifier Child)
			: base(Container, Name)
		{
			this.DeclaredIdType = DeclaredIdType.Alias;
			this.RealId = Child;
		}

        public override Identifier TypeOfSelf
		{
			get { return RealId.TypeOfSelf; }
		}

		public override bool IsEquivalent(Identifier Id)
		{
			return RealId.IsEquivalent(Id);
		}

		public override bool CalculateLayout()
		{
			return RealId.CalculateLayout();
		}
	}

	public abstract class PackedId : Identifier
	{
		public abstract ExpressionNode Extract(PluginRoot Plugin);

		public override Identifier TypeOfSelf
		{
			get { return Children[0]; }
		}

		public PackedId(IdContainer Container, CodeString Name, Identifier Type)
			: base(Container, Name)
		{
			this.Children = new Identifier[] { Type };
		}
	}

	public class PackedMemberId : PackedId
	{
		public ExpressionNode Node;
		public Identifier Member;

        public PackedMemberId(IdContainer Container, CodeString Name, Identifier Type, ExpressionNode Node, Identifier Member)
			: base(Container, Name, Type)
		{
			this.Member = Member;
			this.Node = Node;
		}

		public override ExpressionNode Extract(PluginRoot Plugin)
		{
			var Id = Node.Copy(Plugin, Mode: BeginEndMode.None);
			var Member = Plugin.NewNode(new IdExpressionNode(this.Member, Name));
			if (Id == null || Member == null) return null;

			var NewCh = new ExpressionNode[] { Id, Member };
			return Plugin.NewNode(new OpExpressionNode(Operator.Member, NewCh, Name));
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Software Developer
Hungary Hungary
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions