Click here to Skip to main content
15,886,518 members
Articles / High Performance Computing / Vectorization

Bird Programming Language: Part 1

Rate me:
Please Sign up or sign in to vote.
4.92/5 (129 votes)
1 Jan 2013GPL312 min read 377.4K   2.7K   153  
A new general purpose language that aims to be fast, high level and simple to use.
using System;
using System.Collections.Generic;
using System.Linq;
using Bird.Recognizers;

namespace Bird
{
	[Flags]
	public enum TypeMngrPluginFlags : byte
	{
		None = 0,
		NoWarningOnCastingToSameType = 1,
		AllowConstructorCalls = 2,
		EnableUntypedNodes = 4,
		EnableReadonlyWriting = 8,
		CalculateLayouts = 16,
		EnableAll = NoWarningOnCastingToSameType | AllowConstructorCalls |
			EnableUntypedNodes | EnableReadonlyWriting,
	}

	public class TypeMngrPlugin : ExpressionPlugin
	{
		public Type RetType;
		public TypeMngrPluginFlags Flags;
		public CheckingMode CheckingMode;

		public TypeMngrPlugin(PluginRoot Parent, Type RetType, TypeMngrPluginFlags Flags = TypeMngrPluginFlags.None)
			: base(Parent)
		{
			this.RetType = RetType;
			this.Flags = Flags;

			var Scope = Container.GetParent<CodeScopeNode>(Container.FunctionScope);
			if (Scope != null) CheckingMode = Scope.CheckingMode;
		}

		public override PluginResult End(ref ExpressionNode Node)
		{
			if (Node != null && RetType != null && !Node.Type.IsEquivalent(RetType))
			{
				Node = Convert(Node, RetType, Node.Code);
				if (Node == null) return PluginResult.Failed;
			}

			if (!CheckPropertyIndices(Node)) return PluginResult.Failed;
			return PluginResult.Succeeded;
		}

		bool IsProcessed(Identifier Type)
		{
			var Tuple = Type.UnderlyingStructureOrRealId as TupleType;
			if (Tuple != null && !Tuple.TrueForAllMembers(x => IsProcessed(x.Children[0])))
				return false;

			if (Type.RealId is NonrefArrayType)
			{
				var Array = Type.RealId as NonrefArrayType;
				return !(Array.TypeOfValues is AutomaticType);
			}

			return !(Type.RealId is AutomaticType);
		}

		public bool ProcessType(ExpressionNode Node)
		{
			if ((Flags & TypeMngrPluginFlags.CalculateLayouts) != 0)
			{
				if (Node.Type != null && IsProcessed(Node.Type))
				{
					if (!Node.Type.CalculateLayout())
						return false;
				}
			}

			return true;
		}

		public TypeConversion CanConvert(ExpressionNode Node, Identifier To)
		{
			var RType = Node.Type.RealId as Type;
			var Ret = RType.CanConvert(To);

			if (Ret == TypeConversion.Convertable)
			{
				var TupleTo = To.RealId as TupleType;
				if ((Node.Flags & ExpressionFlags.AutoConvert) != 0)
				{
					Ret = TypeConversion.Automatic;
				}
				else if (TupleTo != null && Expressions.GetOperator(Node) == Operator.Tuple)
				{
					var Found = false;
					var ToMembers = TupleTo.StructuredScope.IdentifierList;

					for (var i = 0; i < Node.Children.Length; i++)
					{
						var Ch = Node.Children[i];
						if ((Ch.Flags & ExpressionFlags.AutoConvert) != 0)
							continue;

						var RChType = Ch.Type.RealId as Type;
						var ToVar = ToMembers[i] as MemberVariable;
						var ToType = ToVar.Children[0];
						if (RChType.CanConvert(ToType) != TypeConversion.Automatic)
							Found = true;
					}

					if (!Found)
						Ret = TypeConversion.Automatic;
				}
			}

			return Ret;
		}

		public ExpressionNode Convert(ExpressionNode Node, Identifier To, CodeString Code)
		{
			var OpFuncRes = ProcessCastOpFunc(ref Node, To, Code, true);
			if (OpFuncRes != SimpleRecResult.Unknown)
			{
				if (OpFuncRes == SimpleRecResult.Succeeded) return Node;
				else if (OpFuncRes == SimpleRecResult.Failed) return null;
				else throw new ApplicationException();
			}

			var ConvRes = CanConvert(Node, To);
			if (ConvRes == TypeConversion.Automatic)
			{
				Node = Expressions.Convert(Node, To, Parent, Code);
				if (Node == null) return null;
			}
			else
			{
				var Message = MessageId.ImplicitlyCast;
				if (ConvRes == TypeConversion.Nonconvertable)
					Message = MessageId.CannotConvert;

				var Types = new string[]
				{
					Node.Type.Name.ToString(), 
					To.Name.ToString()
				};

				State.Messages.Add(Message, Code, Types);
				return null;
			}

			return Node;
		}

		private ExpressionNode CheckCanBeIndexerType(ExpressionNode Node, CodeString Code)
		{
			var SType = Node.Type.RealId as NonFloatType;
			if (SType == null)
			{
				var CastTo = Container.GlobalContainer.CommonIds.GetIdentifier<SignedType>(4);
				return Convert(Node, CastTo, Code);
			}

			return Node;
		}

		TupleType CreateTupleTypeForNodes(ExpressionNode Node)
		{
			var Members = new List<Identifier>();
			for (var i = 0; i < Node.Children.Length; i++)
			{
				var Type = Node.Children[i].Type;
				var MemVar = new MemberVariable(Container, new CodeString(), Type);
				MemVar.Access = Type.Access;
				Members.Add(MemVar);
			}

			return new TupleType(Container, Members);
		}

		bool CheckTupleType(ExpressionNode Node)
		{
			var TupleType = Node.Type.RealId as TupleType;
			var Members = TupleType.StructuredScope.IdentifierList;
			if (Members.Count != Node.Children.Length) return false;

			for (var i = 0; i < Node.Children.Length; i++)
				if (Node.Children[i].Type != Members[i].Children[0]) return false;

			return true;
		}

		PluginResult CheckFunctionCall(ref ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			var Ch = OpNode.Children;
			var Op = OpNode.Operator;

			TypeOfFunction FuncType;
			if (Ch[0].Type.RealId is NonstaticFunctionType)
			{
				var NFuncType = Ch[0].Type.RealId as NonstaticFunctionType;
				FuncType = NFuncType.Child.RealId as TypeOfFunction;
			}
			else if (Ch[0].Type.RealId is TypeOfFunction)
			{
				FuncType = Ch[0].Type.RealId as TypeOfFunction;
			}
			else
			{
				State.Messages.Add(MessageId.CallingNotFunc, Node.Code);
				return PluginResult.Failed;
			}

			if (FuncType.Children.Length != Ch.Length)
			{
				State.Messages.Add(MessageId.ParamCount, Node.Code);
				return PluginResult.Failed;
			}

			var OpCh0 = Ch[0] as OpExpressionNode;
			if (OpCh0 != null && OpCh0.Operator == Operator.Member)
			{
				var BaseId = Expressions.GetIdentifier(Ch[0].Children[0]);
				var FuncId = Expressions.GetIdentifier(Ch[0].Children[1]);
				if (BaseId is BaseVariable && FuncId != null && (FuncId.Flags & IdentifierFlags.Abstract) != 0)
				{
					State.Messages.Add(MessageId.StaticCallAbstract, OpCh0.Code);
					return PluginResult.Failed;
				}
			}

            var ConvertDone = false;
			for (var i = 1; i < FuncType.Children.Length; i++)
			{
				var DstType = FuncType.Children[i].TypeOfSelf;
				if (Ch[i].Type.IsEquivalent(DstType)) continue;
					
				Ch[i] = Convert(Ch[i], DstType, Node.Code);
				if (Ch[i] == null) return PluginResult.Failed;

                ConvertDone = true;
			}

            if (ConvertDone)
            {
                Node = Parent.NewNode(Node);
                return Node == null ? PluginResult.Failed : PluginResult.Ready;
            }

			if (Op == Operator.Call && (Node.Flags & ExpressionFlags.FixedType) == 0)
				Node.Type = FuncType.RetType;

			return PluginResult.Succeeded;
		}

		public SimpleRecResult ProcessCastOpFunc(ref ExpressionNode Node, Identifier To, CodeString Code, bool OnlyImplicit)
		{
			var Global = Container.GlobalContainer;
			if ((Global.Flags & GlobalContainerFlags.StructureMembersParsed) == 0)
				return SimpleRecResult.Unknown;

			var ExplicitFound = false;
			Predicate<Identifier> Func = x =>
			{
				var xFunction = x as Function;
				if (xFunction == null) return false;

				var NameOk = !OnlyImplicit && x.Name.IsEqual("%Operator_Explicit");
				if (NameOk) ExplicitFound = true;

				if (NameOk || x.Name.IsEqual("%Operator_Implicit"))
				{
					var xFuncType = xFunction.Children[0].RealId as TypeOfFunction;
					var xRetType = xFuncType.Children[0].RealId as Type;
					return xRetType.CanConvert(To) != TypeConversion.Nonconvertable;
				}

				return false;
			};

			var List = new List<IdentifierFound>();
			Identifiers.SearchMember(Container, To, null, List, Func);
			Identifiers.SearchMember(Container, Node.Type, null, List, Func);

			if (List.Count > 0)
			{
				if (ExplicitFound)
				{
					for (var i = 0; i < List.Count; i++)
						if (List[i].Identifier.Name.IsEqual("%Operator_Implicit"))
						{
							List.RemoveAt(i);
							i--;
						}
				}

				if (List.Count != 1)
				{
					State.Messages.Add(MessageId.AmbiguousReference, Code);
					return SimpleRecResult.Failed;
				}

				var CallCh = new ExpressionNode[2];
				CallCh[0] = Parent.NewNode(new IdExpressionNode(List[0].Identifier, Code));
				CallCh[1] = Node;

				if (CallCh[0] == null)
					return SimpleRecResult.Failed;

				Node = Parent.NewNode(new OpExpressionNode(Operator.Call, CallCh, Code));
				return Node == null ? SimpleRecResult.Failed : SimpleRecResult.Succeeded;
			}

			return SimpleRecResult.Unknown;
		}

		public PluginResult ProcessOperatorFunctions(ref ExpressionNode Node)
		{
			var Global = Container.GlobalContainer;
			if ((Global.Flags & GlobalContainerFlags.StructureMembersParsed) == 0)
				return PluginResult.Succeeded;

			if ((Node.Flags & ExpressionFlags.DisableOpFunc) != 0)
				return PluginResult.Succeeded;

			var OpNode = Node as OpExpressionNode;
			var Op = OpNode.Operator;
			var Ch = OpNode.Children;

			if (Operators.CanBeOpFunction(Op) && !Ch.TrueForAll(x => x.Type.RealId is NumberType))
			{
				if (Op == Operator.Equality || Op == Operator.Inequality)
				{
					var CIndex = Ch[0] is ConstExpressionNode ? 0 : 1;
					var CNode = Ch[CIndex] as ConstExpressionNode;
					var Type = Ch[1 - CIndex].Type.RealId;

					if (CNode != null && CNode.Value is NullValue && Type is StringType)
						return PluginResult.Succeeded;
				}

				string Name = null;
				Predicate<Identifier> Func = x =>
					{
						if (x.Name.Length > 0 && x.Name[0] == '%')
						{
							if (Name == null)
								Name = "%Operator_" + Op.ToString();

							return x.Name.IsEqual(Name);
						}

						return false;
					};

				var List = new List<IdentifierFound>();
				Identifiers.SearchMember(Container, Ch[0].Type, null, List, Func);
				if (Ch.Length == 2 && !Ch[1].Type.IsEquivalent(Ch[0].Type))
					Identifiers.SearchMember(Container, Ch[1].Type, null, List, Func);

				if (List.Count > 0)
				{
					var Options = GetIdOptions.Default;
					Options.OverloadData = Expressions.GetOperatorSelectData(Ch);

					var Id = Identifiers.SelectIdentifier(State, List, Node.Code, Options);
					if (Id == null) return PluginResult.Failed;

					var CallCh = new ExpressionNode[Ch.Length + 1];
					Ch.CopyTo(CallCh, 1);

					CallCh[0] = Parent.NewNode(new IdExpressionNode(Id, Node.Code));
					if (CallCh[0] == null) return PluginResult.Failed;

					Node = Parent.NewNode(new OpExpressionNode(Operator.Call, CallCh, Node.Code));
					return Node == null ? PluginResult.Failed : PluginResult.Ready;
				}
			}

			if (Op == Operator.Cast)
			{
				var Type = Expressions.GetIdentifier(Ch[1]);
				var CNode = Node;
				Node = Ch[0];

				var Res = ProcessCastOpFunc(ref Node, Type, CNode.Code, false);
				if (Res != SimpleRecResult.Unknown)
				{
					if (Res == SimpleRecResult.Succeeded) return PluginResult.Ready;
					else if (Res == SimpleRecResult.Failed) return PluginResult.Failed;
					else throw new ApplicationException();
				}

				Node = CNode;
			}

			return PluginResult.Succeeded;
		}

		bool CalculateIdentifiers(Identifier Type, ObjectInitNode Node)
		{
			var RetValue = true;
			var Members = Node.Members;
			var Children = Node.Children;

			for (var i = 0; i < Members.Length; i++)
			{
				if (Members[i].Identifier == null)
				{
					var Id = Identifiers.GetMember(State, Type, Members[i].Code);
					if (Id == null) { RetValue = false; continue; }

					Members[i].Identifier = Id;
				}

				var MemberType = Members[i].Identifier.Children[0];
				if (!MemberType.IsEquivalent(Children[i].Type))
				{
					Children[i] = Convert(Children[i], MemberType, Node.Code);
					if (Children[i] == null) RetValue = false;
				}
			}

			return RetValue;
		}

		bool CheckArrayInitNode(Identifier Type, ArrayInitNode Node)
		{
			var RetValue = true;
			var Indices = Node.Indices;
			var Children = Node.Children;
			var ArrayType = Type.RealId as ArrayType;
			var BaseType = ArrayType.Children[0];

			for (var i = 0; i < Indices.Length; i++)
			{
				var ChNode = Children[i] as ExpressionNode;
				if (!ChNode.Type.IsEquivalent(BaseType))
				{
					var OldChNode = ChNode;
					ChNode = Convert(ChNode, BaseType, Node.Code);
					if (ChNode == null) { RetValue = false; continue; }

					Children[i] = ChNode;
					Node.ReplaceChildren(OldChNode, ChNode, false);
				}
			}

			return RetValue;
		}

		bool NeedConvertToNonstaticFunction(ExpressionNode Node)
		{
			return Expressions.IsSelfSpecified(Node) && (Node.Flags & ExpressionFlags.FixedType) == 0;
		}

		ExpressionNode ConvertToNonstaticFunction(ExpressionNode Node, CodeString Code)
		{
			var NewType = new NonstaticFunctionType(Container, Node.Type);
			var TypeNode = Parent.NewNode(new IdExpressionNode(NewType, Code));
			if (TypeNode == null) return null;

			var CastCh = new ExpressionNode[] { Node, TypeNode };
			return Parent.NewNode(new OpExpressionNode(Operator.Cast, CastCh, Code));
		}

		bool ConvertChildrenToNonstaticFunction(ExpressionNode Node)
		{
			for (var i = 0; i < Node.LinkedNodes.Count; i++)
			{
				var LNode = Node.LinkedNodes[i];
				if (NeedConvertToNonstaticFunction(LNode.Node))
				{
					LNode.Node = ConvertToNonstaticFunction(LNode.Node, Node.Code);
					if (LNode.Node == null) return false;
				}
			}

			if (Node.Children != null)
			{
				var Op = Expressions.GetOperator(Node);
				var Ch = Node.Children;

				var Start = 0;
				if (Op == Operator.Call || Op == Operator.NewObject) 
					Start = 1;

				if (Op == Operator.Cast)
				{
					var Global = Container.GlobalContainer;
					var ChiId = Expressions.GetIdentifier(Ch[1]);

					if (ChiId.IsEquivalent(Global.CommonIds.VoidPtr) || 
						ChiId.RealId is NonstaticFunctionType)
					{
						Start = int.MaxValue;
					}
				}

				for (var i = Start; i < Ch.Length; i++)
					if (NeedConvertToNonstaticFunction(Ch[i]))
					{
						Ch[i] = ConvertToNonstaticFunction(Ch[i], Node.Code);
						if (Ch[i] == null) return false;
					}
			}

			return true;
		}

		public PluginResult NewOpNode(ref ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			var Op = OpNode.Operator;
			var Ch = OpNode.Children;

			if (Ch != null)
			{
				for (var i = 0; i < Ch.Length; i++)
					if (Ch[i].Type == null)
					{
						if ((Flags & TypeMngrPluginFlags.EnableUntypedNodes) == 0)
							throw new ApplicationException();

						return PluginResult.Succeeded;
					}
			}

			var OpRes = ProcessOperatorFunctions(ref Node);
			if (OpRes != PluginResult.Succeeded) return OpRes;

			//-------------------------------------------------------------------------------------
			if (Op == Operator.StackAlloc)
			{
				var Global = Container.GlobalContainer;
				if (!(Ch[0].Type.RealId is NonFloatType))
				{
					Ch[0] = Convert(Ch[0], Global.CommonIds.Int32, Node.Code);
					if (Ch[0] == null) return PluginResult.Failed;
				}

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Global.CommonIds.VoidPtr;
			}

			//-------------------------------------------------------------------------------------
			else if (Op == Operator.Is)
			{
				var Ch1Id = Expressions.GetIdentifier(Ch[1]);
				if (Ch1Id == null || !(Ch1Id.RealId is Type))
				{
					State.Messages.Add(MessageId.MustBeType, Ch[1].Code);
					return PluginResult.Failed;
				}

				if (Identifiers.IsSubtypeOrEquivalent(Ch[0].Type, Ch1Id))
					State.Messages.Add(MessageId.ConstExpression, Node.Code, "true");
				else if (!Identifiers.IsSubtypeOf(Ch1Id, Ch[0].Type))
					State.Messages.Add(MessageId.ConstExpression, Node.Code, "false");

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Container.GlobalContainer.CommonIds.Boolean;
			}

			//-------------------------------------------------------------------------------------
			else if (Op == Operator.As)
			{
				var Ch0Type = Ch[0].Type.RealId as Type;
				var Ch1Id = Expressions.GetIdentifier(Ch[1]);
				if (Ch1Id == null || !Identifiers.IsNullableType(Ch1Id))
				{
					State.Messages.Add(MessageId.MustBeClass, Ch[1].Code);
					return PluginResult.Failed;
				}

				var Ch1Type = Ch1Id.RealId as Type;
				if (!Identifiers.IsSubtypeOrEquivalent(Ch1Type, Ch0Type))
					State.Messages.Add(MessageId.ConstExpression, Node.Code, "null");

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Ch1Id;
			}
				
			//-------------------------------------------------------------------------------------
			else if (Operators.IsRefEquality(Op))
			{
				if (!CanOpApplied(OpNode)) return PluginResult.Failed;

				var Res = CastToAppropriateTypes(ref Node);
				if (Res != PluginResult.Succeeded) return Res;

				if (Op == Operator.RefEquality) Op = Operator.Equality;
				else if (Op == Operator.RefInequality) Op = Operator.Inequality;
				else throw new ApplicationException();

				OpNode.Operator = Op;
				Node.Flags |= ExpressionFlags.DisableOpFunc;
				Node = Parent.NewNode(Node);
				return Node == null ? PluginResult.Failed : PluginResult.Ready;
			}

			//-------------------------------------------------------------------------------------
			else if (Operators.IsIncDec(Op))
			{
				if (!CanOpApplied(OpNode)) return PluginResult.Failed;

				var Code = Node.Code;
				if (!Expressions.ProcessTuple(Ch[0], (x, Index) => CheckAssignVar(x, Code)))
					return PluginResult.Failed;

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Ch[0].Type;
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsCast(Op))
			{
				var Ch1Id = Expressions.GetIdentifier(Ch[1]);
				if (Ch1Id == null || !(Ch1Id.RealId is Type))
				{
					State.Messages.Add(MessageId.MustBeType, Ch[1].Code);
					return PluginResult.Failed;
				}

				var RFrom = Ch[0].Type.RealId as Type;
				var RTo = Ch1Id.RealId as Type;

				if ((RTo.TypeFlags & TypeFlags.CanBeVariable) == 0)
				{
					State.Messages.Add(MessageId.InvalidCast, Node.Code);
					return PluginResult.Failed;
				}

				if (RFrom.IsEquivalent(RTo) && (Flags & TypeMngrPluginFlags.NoWarningOnCastingToSameType) == 0)
				{
					if (Ch[0].Type == Ch1Id)
						State.Messages.Add(MessageId.CastToSameType, Node.Code);

					Node = OpNode.Children[0];
					return PluginResult.Ready;
				}

				if (Op == Operator.Reinterpret)
				{
					if (RTo.Size != RFrom.Size)
					{
						State.Messages.Add(MessageId.ReinterpretSize, Node.Code);
						return PluginResult.Failed;
					}
				}
				else if (Op == Operator.Cast)
				{
					if (RFrom is PointerAndLength && RTo is PointerType)
					{
						Ch[0] = ExtractMember(Ch[0], 0, Node.Code);
						if (Ch[0] == null) return PluginResult.Failed;

						var TupleFrom = RFrom as TupleType;
						var Members = TupleFrom.StructuredScope.IdentifierList;
						if (Members[0].TypeOfSelf.IsEquivalent(RTo))
						{
							Node = Ch[0];
							return PluginResult.Ready;
						}

						return Parent.NewNode(ref Node);
					}

					if (RFrom.CanConvert(RTo) == TypeConversion.Nonconvertable)
					{
						var Params = new[] { Ch[0].Type.Name.ToString(), Ch1Id.Name.ToString() };
						State.Messages.Add(MessageId.CannotConvert, Node.Code, Params);
						return PluginResult.Failed;
					}

					var Ch0 = Ch[0];
					var NodeCopy = Node;
					var Res = Expressions.ProcessTuple(Parent, ref Ch0, (x, Index) =>
					{
						var xFrom = x.Type;
						Identifier xTo;
						if (Index == -1)
						{
							xTo = Ch1Id;
						}
						else
						{
							var TupleTo = RTo as TupleType;
							var TupleMembers = TupleTo.StructuredScope.IdentifierList;
							xTo = TupleMembers[Index].Children[0];
						}

						if (xFrom.RealId is ReferenceType && xTo.RealId is ReferenceType)
						{
							var RefxFrom = xFrom.RealId as ReferenceType;
							var RefxTo = xTo.RealId as ReferenceType;
							if (RefxFrom.Child is AutomaticType && RefxFrom.Mode == RefxTo.Mode)
							{
								SetAutoNodeType(x.Children[0], RefxTo.Children[0]);
								x.Type = xTo;
							}
						}

						Identifier BasexTo = null;
						if (xTo.RealId is PointerAndLength)
						{
							var PAndLxTo = xTo.RealId as PointerAndLength;
							BasexTo = PAndLxTo.Child;
						}
						else if (xTo.RealId is ArrayType)
						{
							var ArrxTo = xTo.RealId as ArrayType;
							BasexTo = ArrxTo.Children[0];
						}
						else if (xTo.RealId is PointerType)
						{
							var ArrxTo = xTo.RealId as PointerType;
							BasexTo = ArrxTo.Children[0];
						}

						var ArrxFrom = xFrom.RealId as ArrayType;
						if (BasexTo != null && ArrxFrom != null && ArrxFrom.TypeOfValues is AutomaticType &&
							((BasexTo.RealId as Type).TypeFlags & TypeFlags.CanBeArrayType) != 0)
						{
							var Old = x.Type.RealId;
							if (Old is NonrefArrayType)
							{
								var NonrefOld = Old as NonrefArrayType;
								x.Type = new NonrefArrayType(Container, BasexTo, NonrefOld.Lengths);
							}
							else if (Old is RefArrayType)
							{
								var RefOld = Old as RefArrayType;
								x.Type = new RefArrayType(Container, BasexTo, RefOld.Dimensions);
							}
							else
							{
								throw new ApplicationException();
							}

							return Parent.NewNode(x);
						}

						if (xFrom.RealId is AutomaticType && !(xTo.RealId is AutomaticType))
						{
							if (Expressions.GetOperator(x) == Operator.NewObject)
							{
								var TypeNode = Parent.NewNode(new IdExpressionNode(xTo, x.Code));
								if (TypeNode == null) return null;

								x.Type = xTo;
								x.Children[0] = TypeNode;
								return Parent.NewNode(x);
							}

							SetAutoNodeType(x, xTo);
						}
						else if (xFrom.RealId is TupleType && xTo.RealId is TupleType)
						{
							var TupleFrom = xFrom.RealId as TupleType;
							var TupleTo = xTo.RealId as TupleType;

							var FromMembers = TupleFrom.StructuredScope.IdentifierList;
							var ToMembers = TupleTo.StructuredScope.IdentifierList;

							var Perform = false;
							for (var i = 0; i < FromMembers.Count; i++)
							{
								var FromType = FromMembers[i].TypeOfSelf;
								var ToType = ToMembers[i].TypeOfSelf;

								if (FromType is AutomaticType && !(ToType is AutomaticType))
									Perform = true;
							}

							if (Perform)
							{
								var NewMembers = new List<Identifier>();
								for (var i = 0; i < FromMembers.Count; i++)
								{
									var FromType = FromMembers[i].TypeOfSelf;
									var ToType = ToMembers[i].TypeOfSelf;

									var NewType = FromType.RealId is AutomaticType ? ToType : FromType;
									NewMembers.Add(Identifiers.CreateTupleMember(Container, NewType));
								}

								x.Type = new TupleType(Container, NewMembers);
							}
						}

						return x;
					});

					if (Res == PluginResult.Failed) return Res;
					Ch[0] = Ch0;

					if (Ch0.Type.IsEquivalent(Ch1Id))
					{
						Node = Node.DetachChild(0);
						if ((Node.Flags & ExpressionFlags.FixedType) == 0)
							Node.Type = Ch1Id;

						return PluginResult.Ready;
					}

					if (Res != PluginResult.Succeeded)
					{
						Node = Parent.NewNode(Node);
						return Node == null ? PluginResult.Failed : PluginResult.Ready;
					}
				}
				else
				{
					throw new ApplicationException();
				}

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Ch1Id;
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Tuple)
			{
				for (var i = 0; i < Ch.Length; i++)
					if (!Operators.IsRange(Expressions.GetOperator(Ch[i])))
					{
						var Type = Ch[i].Type.RealId as Type;
						if ((Type.TypeFlags & TypeFlags.CanBeVariable) == 0)
						{
							State.Messages.Add(MessageId.CannotBeThisType, Node.Code);
							return PluginResult.Failed;
						}
					}

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
				{
					if (!Ch.TrueForAll(x => !(x.Type.RealId is VoidType)))
						Node.Type = Container.GlobalContainer.CommonIds.Void;

					else if (Node.Type == null || !CheckTupleType(Node))
						Node.Type = CreateTupleTypeForNodes(Node);
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Array)
			{
				if (Node.Type != null)
				{
					var ArrayType = Node.Type.RealId as NonrefArrayType;
					var BaseType = ArrayType.Children[0];

					if (!(BaseType is AutomaticType))
					{
						for (var i = 0; i < Ch.Length; i++)
							if (!Ch[i].Type.IsEquivalent(BaseType))
							{
								Ch[i] = Convert(Ch[i], BaseType, Node.Code);
								if (Ch[i] == null) return PluginResult.Failed;
							}
					}
				}
				else
				{
					var Groups = Node.Data.Get<NodeGroup>();
					int[] Lengths;

					if (Groups != null)
					{
						Lengths = Expressions.GetArrayLengths(State, Groups);
						if (Lengths == null) return PluginResult.Failed;
					}
					else
					{
						Lengths = new int[] { Ch.Length };
					}

					var Auto = Container.GlobalContainer.CommonIds.Auto;
					Node.Type = new NonrefArrayType(Container, Auto, Lengths);
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsLogical(Op))
			{
				var BoolType = Container.GlobalContainer.CommonIds.Boolean;
				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = BoolType;

				for (var i = 0; i < Ch.Length; i++)
					if (!(Ch[i].Type is BooleanType))
					{
						Ch[i] = Convert(Ch[1], BoolType, Node.Code);
						if (Ch[i] == null) return PluginResult.Failed;
					}
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Assignment)
			{
				if (!CanOpApplied(OpNode)) return PluginResult.Failed;

				var Code = Node.Code;
				var Ch0 = Ch[0].RealNode;
				var Ch1 = Ch[1];
				var NewCheck = false;
				var Res = Expressions.ProcessTuple(Parent, ref Ch1, (x, Index) =>
				{
					if (Index == -1)
					{
						if (Expressions.GetOperator(Ch0) == Operator.Tuple)
						{
							for (var i = 0; i < Ch0.Children.Length; i++)
							{
								var Type = Expressions.GetTupleMemberType(x, i);
								if (!CheckAssignVar(Ch0.Children[i], Type, Code))
									return null;
							}
						}

						return CheckAssignVar(Ch0, x, Code);
					}
					else if (Expressions.GetOperator(Ch0) == Operator.Tuple)
					{
						return CheckAssignVar(Ch0.Children[Index], x, Code);
					}
					else
					{
						NewCheck = true;
					}

					return x;
				});

				if (Res == PluginResult.Failed)
					return PluginResult.Failed;

				Ch[1] = Ch1;
				if (NewCheck)
				{
					Ch[1] = CheckAssignVar(Ch[0], Ch[1], Node.Code);
					if (Ch[1] == null) return PluginResult.Failed;
				}

				if (Res != PluginResult.Succeeded) return Parent.NewNode(ref Node);

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
				{
					if (Expressions.GetOperator(Ch[0]) == Operator.Tuple && !CheckTupleType(Ch[0]))
						Ch[0].Type = CreateTupleTypeForNodes(Ch[0]);

					Node.Type = Ch[0].Type;
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsNewOp(Op))
			{
				if (Op == Operator.NewObject)
				{
					if (!(Node.Type.RealId is AutomaticType))
					{
						for (var i = 0; i < Node.LinkedNodes.Count; i++)
						{
							var LinkedNode = Node.LinkedNodes[i];
							var LNode = LinkedNode.Node;

							if (LNode is ObjectInitNode)
							{
								var InitNode = LNode as ObjectInitNode;
								if (!CalculateIdentifiers(Node.Type, InitNode))
									return PluginResult.Failed;
							}
						}

						if (Ch != null && Ch.Length != 0)
						{
                            var Res = CheckFunctionCall(ref Node);
                            if (Res != PluginResult.Succeeded) return Res;
						}
					}
				}

				else if (Op == Operator.NewArray)
				{
					var ArrayType = Node.Type.RealId as RefArrayType;
					if (!(ArrayType.Children[0].RealId is AutomaticType))
					{
						for (var i = 0; i < Node.LinkedNodes.Count; i++)
						{
							var LinkedNode = Node.LinkedNodes[i];
							var LNode = LinkedNode.Node;

							if (LNode is ObjectInitNode)
							{
								var InitNode = LNode as ObjectInitNode;
								if (!CalculateIdentifiers(Node.Type, InitNode))
									return PluginResult.Failed;
							}
							else if (LNode is ArrayInitNode)
							{
								var InitNode = LNode as ArrayInitNode;
								if (!CheckArrayInitNode(Node.Type, InitNode))
									return PluginResult.Failed;
							}
						}
					}

					for (var i = 0; i < Ch.Length; i++)
					{
						if (!(Ch[i].Type.RealId is NonFloatType))
						{
							var To = Container.GlobalContainer.CommonIds.Int32;
							Ch[i] = Convert(Ch[i], To, Node.Code);
							if (Ch[i] == null) return PluginResult.Failed;
						}
					}
				}

				else
				{
					throw new ApplicationException();
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Call)
            {
                var Res = CheckFunctionCall(ref Node);
                if (Res != PluginResult.Succeeded) return Res;
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Member)
			{
				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
				{
					if (!CanOpApplied(OpNode))
						return PluginResult.Failed;

					Node.Type = Ch[1].Type;
				}

				var IdNode = Ch[1] as IdExpressionNode;
				if (IdNode != null && IdNode.Identifier is Constructor && (Flags & TypeMngrPluginFlags.AllowConstructorCalls) == 0)
				{
					State.Messages.Add(MessageId.CantUseConstructors, Node.Code);
					return PluginResult.Failed;
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Index)
			{
				var Type = Ch[0].Type.RealId;
				if (Type is PointerAndLength)
				{
					Ch[0] = ExtractMember(Ch[0], 0, Node.Code);
					if (Ch[0] == null) return PluginResult.Failed;

					return Parent.NewNode(ref Node);
				}

				if (Type is StringType)
				{
					var StringType = Type as StringType;
					Type = StringType.UnderlyingType;
				}

				if (Type is StructuredType)
				{
					var Options = GetIdOptions.Default;
					Options.EnableMessages = false;
					Options.Func = x => x is Property && !x.Name.IsValid && x.Children.Length > 1;

					var Indexer = Identifiers.GetMember(State, Type, new CodeString(), Options);
					if (Indexer != null)
					{
						var IndexerNode = Parent.NewNode(new IdExpressionNode(Indexer, Node.Code));
						if (IndexerNode == null) return PluginResult.Failed;

						var NewCh = new ExpressionNode[] { Ch[0], IndexerNode };
						Ch[0] = Parent.NewNode(new OpExpressionNode(Operator.Member, NewCh, Node.Code));
						if (Ch[0] == null) return PluginResult.Failed;

						Node = Parent.NewNode(Node);
						return Node == null ? PluginResult.Failed : PluginResult.Ready;
					}
				}

				var MemberId = Expressions.GetMemberIdentifier(Ch[0]);
				var Property = MemberId as Property;
				int IndexCount;

				if (Property != null)
				{
					IndexCount = Property.Children.Length - 1;
					if ((Node.Flags & ExpressionFlags.FixedType) == 0)
						Node.Type = Property.Children[0];

					var BaseId = Expressions.GetIdentifier(Ch[0].Children[0]);
					if (BaseId is BaseVariable && (Property.Flags & IdentifierFlags.Abstract) != 0)
					{
						State.Messages.Add(MessageId.StaticCallAbstract, Ch[0].Code);
						return PluginResult.Failed;
					}
				}
				else if (Type is PointerType)
				{
					var pType = Type as PointerType;
					IndexCount = 1;

					if ((Node.Flags & ExpressionFlags.FixedType) == 0)
						Node.Type = pType.Child;
				}
				else if (Type is ArrayType)
				{
					var Array = Type as ArrayType;
					IndexCount = Array.Dimensions;

					if ((Node.Flags & ExpressionFlags.FixedType) == 0)
						Node.Type = Array.TypeOfValues;
				}
				else
				{
					State.Messages.Add(MessageId.CantOpApplied, Node.Code, Type.Name.ToString());
					return PluginResult.Failed;
				}

				if (IndexCount + 1 != Ch.Length)
				{
					State.Messages.Add(MessageId.ParamCount, Node.Code);
					return PluginResult.Failed;
				}

				for (var i = 1; i <= IndexCount; i++)
				{
					if (Property != null)
					{
						var Param = Property.Children[i] as FunctionParameter;
						var ParamType = Param.TypeOfSelf;

						if (!Ch[i].Type.IsEquivalent(ParamType))
						{
							Ch[i] = Convert(Ch[i], ParamType, Node.Code);
							if (Ch[i] == null) return PluginResult.Failed;
						}
					}
					else
					{
						Ch[i] = CheckCanBeIndexerType(Ch[i], Node.Code);
						if (Ch[i] == null) return PluginResult.Failed;

						if (Ch[i] is ConstExpressionNode && Type is NonrefArrayType)
						{
							var FArr = Type as NonrefArrayType;
							var Const = Ch[i] as ConstExpressionNode;
							var Val = Const.Value as IntegerValue;
							var Int = Val.Value;

							if (FArr.Lengths != null && (Int < 0 || Int >= FArr.Lengths[i - 1]))
							{
								State.Messages.Add(MessageId.IndexOutOfRange, Ch[i].Code);
								return PluginResult.Failed;
							}
						}
					}
				}

				var ConstCh1 = Ch[1] as ConstExpressionNode;
				if (Expressions.GetOperator(Ch[0]) == Operator.Address && ConstCh1 != null && ConstCh1.Integer == 0)
				{
					Ch[0].Children[0].Type = Node.Type;
					Node = Ch[0].Children[0];
					return PluginResult.Ready;
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Address)
			{
				var ChildType = Ch[0].Type.RealId as Type;
				if (ChildType is VoidType || (ChildType.TypeFlags & TypeFlags.CanBePointer) == 0)
				{
					State.Messages.Add(MessageId.InvalidAddressType, Node.Code);
					return PluginResult.Failed;
				}

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = new PointerType(Container, Ch[0].Type);
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Not)
			{
				var Type = Ch[0].Type;
				if (!(Type is BooleanType))
				{
					Type = Container.GlobalContainer.CommonIds.Boolean;
					Ch[0] = Convert(Ch[0], Type, Node.Code);
					if (Ch[0] == null) return PluginResult.Failed;
				}

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Type;
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Condition)
			{
				var Type0 = Ch[0].Type;
				if (!(Type0 is BooleanType))
				{
					Type0 = Container.GlobalContainer.CommonIds.Boolean;
					Ch[0] = Convert(Ch[0], Type0, Node.Code);
					if (Ch[0] == null) return PluginResult.Failed;
				}

				if (!Ch[1].Type.IsEquivalent(Ch[2].Type))
				{
					var RetType = Container.GetRetType(Ch[1].Type, Ch[2].Type);
					if (RetType == null) return PluginResult.Failed;

					if (!Ch[1].Type.IsEquivalent(RetType))
					{
						if ((Ch[1] = Convert(Ch[1], RetType, Node.Code)) == null)
							return PluginResult.Failed;
					}

					if (!Ch[2].Type.IsEquivalent(RetType))
					{
						if ((Ch[2] = Convert(Ch[2], RetType, Node.Code)) == null)
							return PluginResult.Failed;
					}
				}

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
				{
					Node.Type = Ch[1].Type;
					if (Node.Type is AutomaticType)
					{
						State.Messages.Add(MessageId.Untyped, Node.Code);
						return PluginResult.Failed;
					}
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsReference(Op))
			{
				ReferenceMode Mode;
				if (Op == Operator.Reference_Unsafe) Mode = ReferenceMode.Unsafe;
				else if (Op == Operator.Reference_IdMustBeAssigned) Mode = ReferenceMode.IdMustBeAssigned;
				else if (Op == Operator.Reference_IdGetsAssigned) Mode = ReferenceMode.IdGetsAssigned;
				else throw new ApplicationException();

				var ChildType = Ch[0].Type.RealId as Type;
				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = new ReferenceType(Container, Ch[0].Type, Mode);

				if (!(ChildType is AutomaticType) && (ChildType.TypeFlags & TypeFlags.CanBeReference) == 0)
				{
					State.Messages.Add(MessageId.InvalidAddressType, Node.Code);
					return PluginResult.Failed;
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.UnaryPlus)
			{
				Node = Ch[0];
				return PluginResult.Ready;
			}

			//--------------------------------------------------------------------------------------
			else if (Op == Operator.Negation || Op == Operator.Complement)
			{
				if (!CanOpApplied(OpNode)) return PluginResult.Failed;
				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Ch[0].Type;
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsRelEquality(Op))
			{
				var IdCh0 = Ch[0] as IdExpressionNode;
				var IdCh1 = Ch[1] as IdExpressionNode;
				if (IdCh0 != null && IdCh1 != null && IdCh0.Identifier == IdCh1.Identifier)
					State.Messages.Add(MessageId.CmpSameVariable, Node.Code);

				var Res = CastToAppropriateTypes(ref Node);
				if (Res != PluginResult.Succeeded) return Res;

				if (!CanOpApplied(OpNode)) return PluginResult.Failed;
				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Container.GlobalContainer.CommonIds.Boolean;
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsShift(Op))
			{
				if (Ch[0].Type.RealId is AutomaticType)
				{
					State.Messages.Add(MessageId.Untyped, Node.Code);
					return PluginResult.Failed;
				}

				if (!CanOpApplied(OpNode)) return PluginResult.Failed;
				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Ch[0].Type;
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsArithmetical(Op))
			{
				var Ch0Type = Ch[0].Type.RealId as Type;
				var Ch1Type = Ch[1].Type.RealId as Type;

				if ((Ch0Type is StringType) != (Ch1Type is StringType))
				{
					var StringIndex = Ch0Type is StringType ? 0 : 1;
					var NotStringIndex = 1 - StringIndex;
					var NotStringType = NotStringIndex == 0 ? Ch0Type : Ch1Type;

					if (Identifiers.ContainsMember(NotStringType, "ToString", x => x is Function))
					{
						Ch[NotStringIndex] = Expressions.CallToStringSafe(Parent,
							Ch[NotStringIndex], Node.Code);

						if (Ch[NotStringIndex] == null) return PluginResult.Failed;
						return Parent.NewNode(ref Node);
					}
				}

				if (Op == Operator.Add || Op == Operator.Subract)
				{
					var PtrIndex = Ch0Type is PointerType ? 0 : (Ch1Type is PointerType ? 1 : -1);
					var NonPtrIndex = Ch0Type is NonFloatType ? 0 : (Ch1Type is NonFloatType ? 1 : -1);

					if (PtrIndex != -1 && NonPtrIndex != -1)
					{
						if ((Ch[PtrIndex].Type.RealId as PointerType).Child.RealId is VoidType)
						{
							State.Messages.Add(MessageId.CantOpApplied2, Node.Code,
								Ch[0].Type.Name.ToString(), Ch[1].Type.Name.ToString());

							return PluginResult.Failed;
						}

						if ((Node.Flags & ExpressionFlags.FixedType) == 0)
							Node.Type = Ch[PtrIndex].Type;

						return PluginResult.Succeeded;
					}
				}

				if (!CanOpApplied(OpNode)) return PluginResult.Failed;

				var Res = CastToAppropriateTypes(ref Node);
				if (Res != PluginResult.Succeeded) return Res;
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsBitwise(Op))
			{
				if (!CanOpApplied(OpNode)) return PluginResult.Failed;

				var Res = CastToAppropriateTypes(ref Node);
				if (Res != PluginResult.Succeeded) return Res;
			}

			//--------------------------------------------------------------------------------------
			else if (Operators.IsRange(Op))
			{
				if (!CanOpApplied(OpNode)) return PluginResult.Failed;

				var Res = CastToAppropriateTypes(ref Node);
				if (Res != PluginResult.Succeeded) return Res;

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Container.GlobalContainer.CommonIds.Void;
			}

			//--------------------------------------------------------------------------------------
			else if (Op != Operator.NewArray && Op != Operator.Unknown)
			{
				throw new ApplicationException();
			}

			return PluginResult.Succeeded;
		}

		ExpressionNode ExtractMember(ExpressionNode Node, int Index, CodeString Code)
		{
			var Type = Node.Type.RealId as TupleType;
			var Members = Type.StructuredScope.IdentifierList;
			var Member = Parent.NewNode(new IdExpressionNode(Members[Index], Code));
			if (Member == null) return null;

			var Ch = new ExpressionNode[] { Node, Member };
			return Parent.NewNode(new OpExpressionNode(Operator.Member, Ch, Code)); 
		}

		bool CheckAssignVar(ExpressionNode Dst, CodeString Code)
		{
			var DstIdNode = Dst.RealNode as IdExpressionNode;
			if (DstIdNode != null)
			{
				var Id = DstIdNode.Identifier.RealId;
				if (Id != null && (Id.Flags & IdentifierFlags.ReadOnly) != 0 &&
				   (Flags & TypeMngrPluginFlags.EnableReadonlyWriting) == 0)
				{
					State.Messages.Add(MessageId.ReadOnly, Dst.Code);
					return false;
				}
			}
			else if (!Expressions.IsLValue(Dst))
			{
				State.Messages.Add(MessageId.AssignRValue, Code);
				return false;
			}

			return true;
		}

		bool CheckAssignVar(ExpressionNode Dst, Identifier SrcType, CodeString Code)
		{
			if (!CheckAssignVar(Dst, Code))
				return false;

			if (Dst.Type.RealId is AutomaticType)
			{
				if (SrcType.RealId is AutomaticType)
				{
					State.Messages.Add(MessageId.Untyped, Code);
					return false;
				}
				else
				{
					SetAutoNodeType(Dst, SrcType);
				}
			}

			return true;
		}

		private static bool SetAutoNodeType(ExpressionNode Node, Identifier Type, bool AlwaysSet = true)
		{
			if (AlwaysSet)
			{
				Node.Type = Type;
				Node.Flags |= ExpressionFlags.FixedType;
			}

			if (Node is IdExpressionNode)
			{
				Node.Type = Type;

				var IdDst = Node as IdExpressionNode;
				var Var = IdDst.Identifier as Variable;

				if (Var != null && Var.TypeOfSelf.RealId is AutomaticType)
				{
					Var.Children[0] = Type;
					Var.Update();
					return true;
				}
			}

			return false;
		}

		ExpressionNode ResolveAutomaticTypes(ExpressionNode Src, CodeString Code)
		{
			if (Src is OpExpressionNode)
			{
				return ResolveAutomaticTypes_OpNode(Src, Code);
			}

			return Src;
		}

		ExpressionNode ResolveAutomaticTypes_OpNode(ExpressionNode Src, CodeString Code)
		{
			var SrcOp = Expressions.GetOperator(Src);

			//--------------------------------------------------------------------------------------
			if (SrcOp == Operator.Reference_Unsafe || SrcOp == Operator.Reference_IdGetsAssigned ||
				SrcOp == Operator.Reference_IdMustBeAssigned)
			{
				var RefType = Src.Type.RealId as ReferenceType;
				if (RefType.Children[0].RealId is AutomaticType)
				{
					State.Messages.Add(MessageId.Untyped, Code);
					return null;
				}
			}

			//--------------------------------------------------------------------------------------
			if (SrcOp == Operator.NewObject)
			{
				if (Src.Type.RealId is AutomaticType)
				{
					State.Messages.Add(MessageId.Untyped, Code);
					return null;
				}
			}

			//--------------------------------------------------------------------------------------
			else if (SrcOp == Operator.NewArray)
			{
				var ArrayType = Src.Type.RealId as RefArrayType;
				if (ArrayType != null && ArrayType.TypeOfValues is AutomaticType)
				{
					var NewType = (Identifier)null;
					for (var i = 0; i < Src.LinkedNodes.Count; i++)
					{
						var LinkedNode = Src.LinkedNodes[i];
						var LNode = LinkedNode.Node as ArrayInitNode;
						if (LNode == null) continue;

						for (var j = 0; j < LNode.Indices.Length; j++)
						{
							var ChType = LNode.Children[j].Type;
							if (NewType == null)
							{
								NewType = ChType;
							}
							else if (!NewType.IsEquivalent(ChType))
							{
								NewType = null;
								goto CheckEnd;
							}
						}
					}

				CheckEnd:
					var RNewType = NewType == null ? null : NewType.RealId as Type;
					if (RNewType != null && (RNewType.TypeFlags & TypeFlags.CanBeArrayType) != 0)
					{
						Src.Type = new RefArrayType(Container, NewType, ArrayType.Dimensions);
						Src = Parent.NewNode(Src);
					}
					else
					{
						State.Messages.Add(MessageId.ArrayDifferentTypes, Code);
						return null;
					}
				}
			}

			//--------------------------------------------------------------------------------------
			else if (SrcOp == Operator.Array)
			{
				var ArrayType = Src.Type.RealId as NonrefArrayType;
				if (ArrayType != null && ArrayType.TypeOfValues is AutomaticType)
				{
					var NewType = (Identifier)null;
					for (var i = 0; i < Src.Children.Length; i++)
					{
						var ChType = Src.Children[i].Type;
						if (NewType == null)
						{
							NewType = ChType;
						}
						else if (!NewType.IsEquivalent(ChType))
						{
							NewType = null;
							break;
						}
					}

					var RNewType = NewType == null ? null : NewType.RealId as Type;
					if (RNewType != null && (RNewType.TypeFlags & TypeFlags.CanBeArrayType) != 0)
					{
						Src.Type = new NonrefArrayType(Container, NewType, ArrayType.Lengths);
						Src = Parent.NewNode(Src);
					}
					else
					{
						State.Messages.Add(MessageId.ArrayDifferentTypes, Code);
						return null;
					}
				}
			}

			//--------------------------------------------------------------------------------------
			return Src;
		}

		ExpressionNode CheckAssignVar(ExpressionNode Dst, ExpressionNode Src, CodeString Code)
		{
			Dst = Dst.RealNode;
			if (!CheckAssignVar(Dst, Src.Type, Code)) 
				return null;

			if (Src is IdExpressionNode && Dst is IdExpressionNode)
			{
				var IdDst = Dst as IdExpressionNode;
				var IdSrc = Src as IdExpressionNode;

				if (IdDst.Identifier == IdSrc.Identifier)
					State.Messages.Add(MessageId.AssignSameVar, Code);
			}

			if (!Dst.Type.IsEquivalent(Src.Type))
			{
				if (Dst.Type == null || Src.Type == null)
					return null;

				Src = Convert(Src, Dst.Type, Code);
				if (Src == null) return null;
			}

			return Src;
		}

		public Identifier CastToAppropriateTypes(ref Identifier Type0, bool AutoConvert0, ref Identifier Type1, bool AutoConvert1)
		{
			var RealId0 = Type0.RealId;
			var RealId1 = Type1.RealId;

			if (RealId0 is AutomaticType) { Type0 = Type1; return Type0; }
			if (RealId1 is AutomaticType) { Type1 = Type0; return Type0; }

			if (RealId0 is TupleType) { Type1 = Type0; return Type0; }
			if (RealId1 is TupleType) { Type0 = Type1; return Type0; }
			
			if (RealId0 is NumberType && RealId1 is NumberType)
			{
				if (AutoConvert0 && (!(RealId0 is FloatType) || RealId1 is FloatType))
				{ 
					Type0 = Type1; 
					return Type0; 
				}
				else if (AutoConvert1 && (!(RealId1 is FloatType) || RealId0 is FloatType))
				{ 
					Type1 = Type0; 
					return Type0; 
				}
			}

			if (RealId0 is CharType) return Type0;
			if (RealId1 is CharType) return Type1;

			if (RealId0 is PointerType) return Type0;
			if (RealId1 is PointerType) return Type1;

			if (RealId0 is NumberType && RealId1 is NumberType)
			{
				if (RealId0.IsEquivalent(RealId1)) return RealId0;
				Type0 = Type1 = Container.GetNumberRetType(Type0, Type1);
			}

			return Type0;
		}

		bool CheckVariablesTypes(List<Identifier> Identifiers, List<Identifier> Types)
		{
			if (Identifiers.Count != Types.Count)
				throw new ArgumentException();

			for (var i = 0; i < Identifiers.Count; i++)
			{
				if (!Identifiers[i].TypeOfSelf.IsEquivalent(Types[i])) 
					return false;
			}

			return true;
		}

		PluginResult CastToAppropriateTypes(ref ExpressionNode Node)
		{
			var Ch = Node.Children;
			var Type0 = Ch[0].Type;
			var Type1 = Ch[1].Type;

			if (Type0.RealId is TupleType && Type1.RealId is TupleType)
			{
				var Tuple0 = Type0.RealId as TupleType;
				var Tuple1 = Type1.RealId as TupleType;

				var Members0 = Tuple0 != null ? Tuple0.StructuredScope.IdentifierList 
											  : new AutoAllocatedList<Identifier>();

				var Members1 = Tuple1 != null ? Tuple1.StructuredScope.IdentifierList 
											  : new AutoAllocatedList<Identifier>();

				if (Members0.Count == Members1.Count)
				{
					var Check = false;
					var RetTypes = new List<Identifier>();
					var Ch0Types = new List<Identifier>();
					var Ch1Types = new List<Identifier>();

					for (var i = 0; i < Members0.Count; i++)
					{
						var MType0 = Members0[i].Children[0];
						var MType1 = Members1[i].Children[0];

						var MRetType = CastToAppropriateTypes(ref MType0, false, ref MType1, false);
						if (!MType0.IsEquivalent(Members0[i].TypeOfSelf)) Check = true;
						if (!MType1.IsEquivalent(Members1[i].TypeOfSelf)) Check = true;

						Ch0Types.Add(MType0);
						Ch1Types.Add(MType1);

						if (MRetType.RealId is AutomaticType)
						{
							State.Messages.Add(MessageId.Untyped, Node.Code);
							return PluginResult.Failed;
						}

						RetTypes.Add(MRetType);
					}

					if (Check)
					{
						var LConvertDone = false;
						if (Members0.List == null || !CheckVariablesTypes(Members0.List, Ch0Types))
						{
							var NewType = Identifiers.CreateTupleFromTypes(Container, Ch0Types);
							Ch[0] = Convert(Ch[0], NewType, Node.Code);
							if (Ch[0] == null) return PluginResult.Failed;

							LConvertDone = true;
						}

						if (Members1.List == null || !CheckVariablesTypes(Members1.List, Ch1Types))
						{
							var NewType = Identifiers.CreateTupleFromTypes(Container, Ch1Types);
							Ch[1] = Convert(Ch[1], NewType, Node.Code);
							if (Ch[1] == null) return PluginResult.Failed;

							LConvertDone = true;
						}

						if (LConvertDone)
						{
							Node = Parent.NewNode(Node);
							return Node == null ? PluginResult.Failed : PluginResult.Ready;
						}
					}
					
					if (Members0.List != null && CheckVariablesTypes(Members0.List, RetTypes))
					{
						if ((Node.Flags & ExpressionFlags.FixedType) == 0)
							Node.Type = Type0;

						return PluginResult.Succeeded;
					}

					if (Members1.List != null && CheckVariablesTypes(Members1.List, RetTypes))
					{
						if ((Node.Flags & ExpressionFlags.FixedType) == 0)
							Node.Type = Type1;

						return PluginResult.Succeeded;
					}

					if ((Node.Flags & ExpressionFlags.FixedType) == 0)
						Node.Type = Identifiers.CreateTupleFromTypes(Container, RetTypes);

					return PluginResult.Succeeded;
				}
			}

			var RetType = CastToAppropriateTypes(ref Type0, (Ch[0].Flags & ExpressionFlags.AutoConvert) != 0,
				ref Type1, (Ch[1].Flags & ExpressionFlags.AutoConvert) != 0);

			if (RetType.RealId is AutomaticType)
			{
				State.Messages.Add(MessageId.Untyped, Node.Code);
				return PluginResult.Failed;
			}

			var ConvertDone = false;
			if (!Type0.IsEquivalent(Ch[0].Type))
			{
				Ch[0] = Convert(Ch[0], Type0, Node.Code);
				if (Ch[0] == null) return PluginResult.Failed;
                
				ConvertDone = true;
			}

			if (!Type1.IsEquivalent(Ch[1].Type))
			{
				Ch[1] = Convert(Ch[1], Type1, Node.Code);
				if (Ch[1] == null) return PluginResult.Failed;
				
                ConvertDone = true;
			}

			if (ConvertDone)
			{
				Node = Parent.NewNode(Node);
				return Node == null ? PluginResult.Failed : PluginResult.Ready;
			}

			if ((Node.Flags & ExpressionFlags.FixedType) == 0)
				Node.Type = RetType;

			return PluginResult.Succeeded;
		}

		public bool CanOpApplied(OpExpressionNode Node)
		{
			var Ch = Node.Children;
			var Op = Node.Operator;

			if ((Ch[0].Flags & ExpressionFlags.AutoConvert) == 0 &&
				(Ch.Length < 2 || (Ch[1].Flags & ExpressionFlags.AutoConvert) == 0))
			{
				var SrcType = Ch.Length > 1 ? Ch[1].Type.RealId as Type : null;
				if (!(Ch[0].Type.RealId as Type).CanOpApplied(Op, SrcType))
				{
					if (Ch.Length > 1 && SrcType != null && !Ch[0].Type.IsEquivalent(SrcType))
					{
						State.Messages.Add(MessageId.CantOpApplied2, Node.Code,
							Ch[0].Type.Name.ToString(), SrcType.Name.ToString());
					}
					else
					{
						State.Messages.Add(MessageId.CantOpApplied, Node.Code, Ch[0].Type.Name.ToString());
					}

					return false;
				}
			}

			return true;
		}

		Identifier GetNonrefType(Identifier Type)
		{
			var RefType = Type.RealId as ReferenceType;
			if (RefType != null) return RefType.Children[0];
			return Type;
		}

		bool IsUnlinkableNode(ExpressionNode Node)
		{
			var Op = Expressions.GetOperator(Node);
			var Ch = Node.Children;

			if (Op == Operator.Index || Op == Operator.Member)
			{
				for (var i = 0; i < Ch.Length; i++)
					if (Ch[i] is OpExpressionNode) return false;

				if (Op == Operator.Member && Ch[1] is IdExpressionNode)
				{
					var IdCh1 = Ch[1] as IdExpressionNode;
					if (IdCh1.Identifier.RealId is Property) return false;
				}

				return true;
			}
			else if (Node is IdExpressionNode)
			{
				var IdNode = Node as IdExpressionNode;
				return !(IdNode.Identifier.RealId is Property);
			}

			return !(Node is OpExpressionNode);
		}

		bool NeedToResolveAutomaticTypes(ExpressionNode Node)
		{
			var Op = Expressions.GetOperator(Node);
			var Ch = Node.Children;

			if (Op == Operator.NewObject) return Ch == null || Ch.Length == 0;
			else if (Op == Operator.Assignment) return Ch[0].Type.RealId is AutomaticType;
			else return Op != Operator.Cast && Op != Operator.Tuple && Op != Operator.Call;
		}

		PluginResult ResolveAutomaticTypes_Tuple(ref ExpressionNode Node, CodeString Code)
		{
			return Expressions.ProcessTuple(Parent, ref Node, (x, Index) =>
				ResolveAutomaticTypes(x, Code));
		}
		
		public override PluginResult NewNode(ref ExpressionNode Node)
		{
			if (CheckingMode != CheckingMode.Default && Node.CheckingMode == CheckingMode.Default)
				Node.CheckingMode = CheckingMode;
			
			for (var i = 0; i < Node.LinkedNodes.Count; i++)
			{
				var LNode = Node.LinkedNodes[i];
				LNode.Node = ResolveAutomaticTypes(LNode.Node, Node.Code);
				if (LNode.Node == null) return PluginResult.Failed;

				if ((LNode.Flags & LinkedNodeFlags.PostComputation) != 0)
				{
					if (LNode.Node.Type.RealId is VoidType)
						throw new ApplicationException();
				}

				if ((LNode.Flags & LinkedNodeFlags.NotRemovable) == 0 && LNode.LinkingCount == 0)
				{
					Node.LinkedNodes.RemoveAt(i);
					i--;
				}
			}

			//-------------------------------------------------------------------------------------
			if (NeedToResolveAutomaticTypes(Node))
			{
				var CallNewNode = false;
				if (Node.Children != null)
				{
					var Ch = Node.Children;
					for (var i = 0; i < Ch.Length; i++)
					{
						var Chi = Ch[i];
						var Res = ResolveAutomaticTypes_Tuple(ref Chi, Node.Code);
						if (Res == PluginResult.Failed) return Res;
						if (Res != PluginResult.Succeeded) CallNewNode = true;
					}
				}

				if (CallNewNode)
				{
					Node = Parent.NewNode(Node);
					return Node == null ? PluginResult.Failed : PluginResult.Ready;
				}
			}

			//------------------------------------------------------------------------------------
			if (!ConvertChildrenToNonstaticFunction(Node))
				return PluginResult.Failed;

			//--------------------------------------------------------------------------------------
			if (Node is ScopeExpressionNode)
			{
				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
				{
					var SNode = Node as ScopeExpressionNode;
					if (SNode.ReturnVar != null) Node.Type = SNode.ReturnVar.Children[0];
					else Node.Type = Container.GlobalContainer.CommonIds.Void;
				}
			}

			//--------------------------------------------------------------------------------------
			else if (Node is IdExpressionNode)
			{
				var IdNode = Node as IdExpressionNode;
				var Id = IdNode.Identifier;
				Id.SetUsed();

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					IdNode.Type = GetNonrefType(Id.TypeOfSelf);
			}

			//--------------------------------------------------------------------------------------
			else if (Node is OpExpressionNode)
			{
				var Res = NewOpNode(ref Node);
				if (Res != PluginResult.Succeeded)
					return Res;
			}
			
			//--------------------------------------------------------------------------------------
			else if (Node is LinkingNode)
			{
				var LinkingNode = Node as LinkingNode;
				var LinkedNode = LinkingNode.LinkedNode;
				var RLinkedNode = LinkedNode.Node;

				if ((LinkedNode.Flags & LinkedNodeFlags.NotRemovable) == 0)
				{
					if (Expressions.GetOperator(RLinkedNode) != Operator.Assignment)
					{
						if (IsUnlinkableNode(RLinkedNode))
						{
							Node = RLinkedNode.Copy(Parent, Mode: BeginEndMode.None);
							return Node == null ? PluginResult.Failed : PluginResult.Ready;
						}
					}
					else if (IsUnlinkableNode(RLinkedNode.Children[0]))
					{
						LinkedNode.LinkingCount++;
						Node = RLinkedNode.Children[0].Copy(Parent, Mode: BeginEndMode.None);
						if (Node == null) return PluginResult.Failed;

						Node.Flags &= ~ExpressionFlags.IdMustBeAssigned;
						return PluginResult.Ready;
					}
				}

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = RLinkedNode.Type;

				LinkedNode.LinkingCount++;
			}

			//--------------------------------------------------------------------------------------
			else if (Node is DataPointerNode)
			{
				var IdDescNode = Node as DataPointerNode;
				if (IdDescNode.DescPointerType == DataPointerType.Identifier)
				{
					var Id = IdDescNode.Id;
					Id.SetUsed();

					if (!(Id.RealId is Type) && Id.Container.FunctionScope != null)
					{
						State.Messages.Add(MessageId.IdDescPtrFromLocal, Node.Code);
						return PluginResult.Failed;
					}
					
					var RealOrUnder = Id.UnderlyingStructureOrSelf;
					if (RealOrUnder is Type && RealOrUnder.DeclaredIdType == DeclaredIdType.Unknown)
					{
						var Global = Container.GlobalContainer;
						IdDescNode.Id = Id = Global.GetTypeAlias((Id as Type));
						if (Id == null) return PluginResult.Failed;
					}
				}
				else if (IdDescNode.DescPointerType != DataPointerType.IncBin &&
					IdDescNode.DescPointerType != DataPointerType.Assembly)
				{
					throw new NotImplementedException();
				}

				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Container.GlobalContainer.CommonIds.VoidPtr;
			}

			//--------------------------------------------------------------------------------------
			else if (Node is LabelExpressionNode)
			{
				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Container.GlobalContainer.CommonIds.VoidPtr;
			}

			//--------------------------------------------------------------------------------------
			else if (Node is ObjectInitNode || Node is ArrayInitNode)
			{
				if ((Node.Flags & ExpressionFlags.FixedType) == 0)
					Node.Type = Container.GlobalContainer.CommonIds.Void;
			}

			//--------------------------------------------------------------------------------------
			else if (Node is ConstExpressionNode || Node is StrExpressionNode ||
				Node is MacroExpressionNode || Node is MacroArgNode || Node is NamedParameterNode)
			{
				return PluginResult.Succeeded;
			}

			//--------------------------------------------------------------------------------------
			if (Node.Type == null && (Flags & TypeMngrPluginFlags.EnableUntypedNodes) == 0)
				throw new ApplicationException();

			if (!ProcessType(Node)) return PluginResult.Failed;
			if (!Node.CheckChildren(CheckChild)) return PluginResult.Failed;
			return PluginResult.Succeeded;
		}

		public bool CheckChild(ExpressionNode Node)
		{
			if (!CheckPropertyIndices(Node)) return false;
			return true;
		}

		public bool CheckPropertyIndices(ExpressionNode Node)
		{		
			var Id = Expressions.GetMemberIdentifier(Node);
			if (Id == null) return true;

			var Property = Id.RealId as Property;
			if (Property != null && Property.Children.Length > 1)
			{
				State.Messages.Add(MessageId.MissingPropertyIndices, Node.Code);
				return false;
			}

			return true;
		}
	}
}

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