Click here to Skip to main content
15,883,883 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.Numerics;

namespace Bird
{
	public struct ConvStrToNumberOptions
	{
		public ConstValueType Type;
		public LetterCase LetterCase;
		public StringSlice Number;
		public int Radix;
		public bool EnableENotation;
		public bool Sign;

		public static ConvStrToNumberOptions Default
		{
			get
			{
				var Ret = new ConvStrToNumberOptions();
				Ret.Radix = 10;
				Ret.LetterCase = LetterCase.Both;
				Ret.EnableENotation = true;
				return Ret;
			}
		}
	}

	public struct ConvNumberPartsOptions
	{
		public ConstValueType Type;
		public BigInteger Number;
		public BigInteger Fraction;
		public BigInteger ENotation;
		public int Radix;
		public int FractionLength;
		public bool UseFraction;

		public static ConvNumberPartsOptions Default
		{
			get
			{
				var Ret = new ConvNumberPartsOptions();
				Ret.Radix = 10;
				return Ret;
			}
		}
	}

	public delegate ExpressionNode ExtractTupleOpFunc(int Index, ExpressionNode[] Ch);

	public interface IFind2Handler
	{
		bool IsAcceptable(IdContainer Container, StringSlice String);
	}

	public static class RecognizerHelper
	{
		public static StringSlice CutOffSign(StringSlice String)
		{
			for (var i = 0; i < String.Length; i++)
			{
				var Char = String[i];
				if (Char == '+' || Char == '-') continue;
				return String.Substring(i);
			}

			return String;
		}

		public static CodeString CutOffSign(CodeString String)
		{
			for (var i = 0; i < String.Length; i++)
			{
				var Char = String[i];
				if (Char == '+' || Char == '-') continue;
				return String.Substring(i);
			}

			return String;
		}

		public static bool GetSign(ref StringSlice String)
		{
			var Negative = false;
			for (var i = 0; i < String.Length; i++)
			{
				var Char = String[i];
				if (Char == '-')
				{
					Negative = !Negative;
				}
				else
				{
					if (Char == '+') continue;

					String = String.Substring(i);
					break;
				}
			}

			return Negative;
		}

		public static bool GetSign(ref CodeString String)
		{
			var Negative = false;
			for (var i = 0; i < String.Length; i++)
			{
				var Char = String[i];
				if (Char == '-')
				{
					Negative = !Negative;
				}
				else
				{
					if (Char == '+') continue;

					if (i != 0)
						String = String.Substring(i);

					break;
				}
			}

			return Negative;
		}

		public static SimpleRecResult ConvStrToNumber(CompilerState State, CodeString Code,
			ConvStrToNumberOptions Options, out ConstValue Value)
		{
			Value = null;
			var Radix = Options.Radix;
			var LetterCase = Options.LetterCase;

			var Options2 = new ConvNumberPartsOptions();
			Options2.Radix = Radix;
			Options2.Type = Options.Type;

			var Number = Options.Number;
			var Negative = GetSign(ref Number);
			if (Options.Sign) Negative = !Negative;

			var PointChk = Number;
			var ENotationPos = -1;

			if (Options.EnableENotation)
			{
				if (Options.LetterCase != LetterCase.OnlyLower)
					ENotationPos = PointChk.Find('e');

				if (ENotationPos == -1 && Options.LetterCase != LetterCase.OnlyUpper)
					ENotationPos = PointChk.Find('E');
			}

			if (ENotationPos != -1)
			{
				PointChk = PointChk.Substring(0, ENotationPos);
				var ENotation = Code.Substring(ENotationPos + 1);
				var ENegative = GetSign(ref ENotation);

				if (!ENotation.ToNumber(Radix, LetterCase, out Options2.ENotation))
					return SimpleRecResult.Unknown;

				Options2.UseFraction = true;
				if (ENegative) Options2.ENotation = -Options2.ENotation;
			}

			var Point = PointChk.Find('.');
			if (Point == -1)
			{
				if (!PointChk.ToNumber(Radix, LetterCase, out Options2.Number))
					return SimpleRecResult.Unknown;

				if (Negative) Options2.Number = -Options2.Number;
			}
			else
			{
				var Left = PointChk.Substring(0, Point);
				var Right = PointChk.Substring(Point + 1);
				Options2.UseFraction = true;
				Options2.FractionLength = Right.Length;

				if (!Left.ToNumber(Radix, LetterCase, out Options2.Number))
					return SimpleRecResult.Unknown;
				if (!Right.ToNumber(Radix, LetterCase, out Options2.Fraction))
					return SimpleRecResult.Unknown;

				if (Negative)
				{
					Options2.Number = -Options2.Number;
					Options2.Fraction = -Options2.Fraction;
				}
			}

			return ConvNumberParts(State, Code, Options2, out Value);
		}

		public static SimpleRecResult ConvNumberParts(CompilerState State, CodeString Code,
			ConvNumberPartsOptions Options, out ConstValue Value)
		{
			Value = null;
			var Number = Options.Number;
			var Fraction = Options.Fraction;
			var Type = Options.Type;
			var ENotation = Options.ENotation;
			var Radix = Options.Radix;
			var UseFraction = Options.UseFraction;

			if (Type == ConstValueType.Unknown)
			{
				if (UseFraction) Type = ConstValueType.Double;
				else Type = ConstValueType.Integer;
			}
			else if (UseFraction && Type != ConstValueType.Double && Type != ConstValueType.Float)
			{
				State.Messages.Add(MessageId.ConstOutOfRange, Code);
				return SimpleRecResult.Failed;
			}

			if (Type == ConstValueType.Double || Type == ConstValueType.Float)
			{
				var Ret = (double)Number;
				if (UseFraction)
				{
					var N = BigInteger.Pow(Radix, Options.FractionLength);
					Ret += (double)Fraction / (double)N;
				}

				if (ENotation > 0)
				{
					if (ENotation > int.MaxValue)
					{
						State.Messages.Add(MessageId.ConstOutOfRange, Code);
						return SimpleRecResult.Failed;
					}

					for (var i = 0; i < (int)ENotation; i++)
						Ret *= Radix;
				}
				else if (ENotation < 0)
				{
					if (ENotation < int.MinValue)
					{
						State.Messages.Add(MessageId.ConstOutOfRange, Code);
						return SimpleRecResult.Failed;
					}

					for (var i = (int)ENotation; i < 0; i++)
						Ret /= Radix;
				}

				if (Double.IsInfinity(Ret))
				{
					State.Messages.Add(MessageId.ConstOutOfRange, Code);
					return SimpleRecResult.Failed;
				}

				if (Type == ConstValueType.Double) Value = new DoubleValue(Ret);
				else Value = new FloatValue((float)Ret);
				return SimpleRecResult.Succeeded;
			}
			else if (Type == ConstValueType.Integer)
			{
				Value = new IntegerValue(Number);
				return SimpleRecResult.Succeeded;
			}
			else
			{
				throw new ApplicationException();
			}
		}

		public static CodeString ExtractBracket(CompilerState State, CodeString ErrCode,
			char Bracket, ref CodeString Code, bool Back = false, bool EnableMessages = true)
		{
			if (Code.Length == 0)
			{
				State.Messages.Add(MessageId.DeficientExpr, ErrCode);
				return new CodeString();
			}

			if (Back)
			{
				if (Code[Code.Length - 1] != Bracket)
				{
					State.Messages.Add(MessageId.DeficientExpr, ErrCode);
					return new CodeString();
				}

				var BracketPos = Code.GetBracketPos(State, true, EnableMessages);
				if (BracketPos == -1) return new CodeString();

				var InsideBracket = Code.Substring(BracketPos + 1, Code.Length - BracketPos - 2).Trim();
				if (!InsideBracket.IsValid) return new CodeString();

				Code = Code.Substring(0, BracketPos).Trim();
				return InsideBracket;
			}
			else
			{
				if (Code[0] != Bracket)
				{
					State.Messages.Add(MessageId.DeficientExpr, ErrCode);
					return new CodeString();
				}

				var BracketPos = Code.GetBracketPos(State, false, EnableMessages);
				if (BracketPos == -1) return new CodeString();

				var InsideBracket = Code.Substring(1, BracketPos - 1).Trim();
				if (!InsideBracket.IsValid) return new CodeString();

				Code = Code.Substring(BracketPos + 1).Trim();
				return InsideBracket;
			}
		}

		public static SimpleRecResult ExtractBracket(CompilerState State, char Bracket, ref CodeString Code, 
			out CodeString Word, out CodeString InsideBracket, bool EnableMessages = true)
		{
            Word = Code.Word(Handlers: State.Language.GlobalHandlers);
			if (Word.Length == 0)
			{
				InsideBracket = new CodeString();
				return SimpleRecResult.Unknown;
			}

			InsideBracket = ExtractBracket(State, Word, Bracket, ref Code, false, EnableMessages);
			return InsideBracket.IsValid ? SimpleRecResult.Succeeded : SimpleRecResult.Failed;
		}

		public static SimpleRecResult ExtractBracket(CompilerState State, string[] Find, string[] Skip, 
			char Bracket, ref CodeString Code, out FindResult Result, out CodeString InsideBracket, 
			out CodeString CuttedCode, bool EnableMessages = true)
		{
			var OldCode = Code;
			Result = Code.StartsWith(Find, Skip);
			if (Result.Index == -1)
			{
				InsideBracket = new CodeString();
				CuttedCode = new CodeString();
				return SimpleRecResult.Unknown;
			}

			var Word = Code.Substring(0, Result.String.Length);
			Code = Code.Substring(Result.String.Length).Trim();

			InsideBracket = ExtractBracket(State, Word, Bracket, ref Code, false, EnableMessages);
			CuttedCode = Code.Substring(OldCode.Length - Code.Length);
			return InsideBracket.IsValid ? SimpleRecResult.Succeeded : SimpleRecResult.Failed;
		}

		public static SimpleRecResult ExtractBracket(CompilerState State, string Find, char Bracket, 
			ref CodeString Code, out CodeString InsideBracket, out CodeString CuttedCode, bool EnableMessages = true)
		{
			var OldCode = Code;
			if (!Code.StartsWith(Find))
			{
				InsideBracket = new CodeString();
				CuttedCode = new CodeString();
				return SimpleRecResult.Unknown;
			}

			var Word = Code.Substring(0, Find.Length);
			Code = Code.Substring(Find.Length).Trim();

			InsideBracket = ExtractBracket(State, Word, Bracket, ref Code, false, EnableMessages);
			CuttedCode = OldCode.Substring(OldCode.Length - Code.Length);
			return InsideBracket.IsValid ? SimpleRecResult.Succeeded : SimpleRecResult.Failed;
		}

		public static string ProcessString(CodeString Code, PluginRoot Plugin, char Char)
		{
			var Ret = "";
			var RetValue = true;
			var LastPos = 0;
			var String = Code.ToString();

			for (var i = 0; i < String.Length; i++)
			{
				if (String[i] == Char)
				{
					var Length = -1;
					Ret += String.Substring(LastPos, i - LastPos);

					if (i < String.Length - 1)
					{
						var NextChar = Code[i + 1];
						if (char.IsDigit(NextChar))
						{
							var CharCode = NextChar - '0';
							Length = 1;

							for (var j = i + 2; j < String.Length; j++)
							{
								if (char.IsDigit(Code[j]))
								{
									Length++;
									if (Length < 6)
									{
										CharCode *= 10;
										CharCode += Code[j] - '0';
									}
								}
								else
								{
									break;
								}
							}

							if (Length > 5 || CharCode > (int)char.MaxValue)
							{
								var PStr = Code.Substring(i + 1, Length);
								Plugin.State.Messages.Add(MessageId.ConstOutOfRange, PStr);
								RetValue = false;
							}

							Ret += (char)CharCode;
						}
						else
						{
							Length = 1;
							if (NextChar == 't') Ret += "\t";
							else if (NextChar == 'q') Ret += "\"";
							else if (NextChar == 'r') Ret += "\r";
							else if (NextChar == 'n') Ret += "\n";
							else if (NextChar == Char) Ret += Char;
							else Length = -1;
						}
					}

					if (Length == -1)
					{
						var PStrChar = Code.Substring(i, 1);
						Plugin.State.Messages.Add(MessageId.InvalidEscapeSequence, PStrChar);
						RetValue = false;
					}
					else
					{
						LastPos = i + Length + 1;
						i += Length;
					}
				}
			}

			if (!RetValue) return null;
			Ret += String.Substring(LastPos);
			return Ret;
		}

		public static bool SplitToParameters(CompilerState State, CodeString Self, string Separator,
			List<CodeString> Ret, bool EnableMessages = true, bool EnableEmpty = false)
		{
			Self = Self.Trim();
			if (Self.Length == 0)
				return true;

			var SkipHandlers = State.Language.GlobalHandlers;
			var RetValue = true;
			var WasSeparator = true;
			var Sep = new CodeString();

			foreach (var e in Self.EnumSplit(Separator, StringSplitOptions.RemoveEmptyEntries, true, SkipHandlers))
			{
				if (e.IsSeparator)
				{
					if (WasSeparator)
					{
						if (!EnableEmpty)
						{
							if (EnableMessages) State.Messages.Add(MessageId.MissingParam, Sep);
							RetValue = false;
						}

						Ret.Add(new CodeString());
					}

					Sep = Self.Substring(e.String);
					WasSeparator = true;
				}
				else
				{
					Ret.Add(Self.Substring(e.String));
					Sep = new CodeString();
					WasSeparator = false;
				}
			}

			if (WasSeparator)
			{
				if (!EnableEmpty)
				{
					if (EnableMessages) State.Messages.Add(MessageId.MissingParam, Sep);
					RetValue = false;
				}

				Ret.Add(new CodeString());
			}

			return RetValue;
		}

		public static bool SplitToParameters(CompilerState State, CodeString Self, char Separator,
			List<CodeString> Ret, bool EnableMessages = true, bool EnableEmpty = false)
		{
			Self = Self.Trim();
			if (Self.Length == 0)
				return true;

			if (Self.Find(Separator) == -1)
			{
				Ret.Add(Self);
				return true;
			}

			var SkipHandlers = State.Language.GlobalHandlers;
			var RetValue = true;
			var WasSeparator = true;
			var Sep = new CodeString();

			foreach (var e in Self.EnumSplit(Separator, StringSplitOptions.RemoveEmptyEntries, true, SkipHandlers))
			{
				if (e.IsSeparator)
				{
					if (WasSeparator)
					{
						if (!EnableEmpty)
						{
							if (EnableMessages) State.Messages.Add(MessageId.MissingParam, Sep);
							RetValue = false;
						}

						Ret.Add(new CodeString());
					}

					Sep = Self.Substring(e.String);
					WasSeparator = true;
				}
				else
				{
					Ret.Add(Self.Substring(e.String));
					Sep = new CodeString();
					WasSeparator = false;
				}
			}

			if (WasSeparator)
			{
				if (!EnableEmpty)
				{
					if (EnableMessages) State.Messages.Add(MessageId.MissingParam, Sep);
					RetValue = false;
				}

				Ret.Add(new CodeString());
			}

			return RetValue;
		}

		public static CodeString[] SplitToParameters(CompilerState State, CodeString Self,
			char Separator, bool EnableMessages = true, bool EnableEmpty = false)
		{
			var Ret = new List<CodeString>();
			if (!SplitToParameters(State, Self, Separator, Ret, EnableMessages, EnableEmpty))
				return null;

			return Ret.ToArray();
		}

		public static CodeString[] SplitToParameters(CompilerState State, CodeString Self,
			string Separator, bool EnableMessages = true, bool EnableEmpty = false)
		{
			var Ret = new List<CodeString>();
			if (!SplitToParameters(State, Self, Separator, Ret, EnableMessages, EnableEmpty))
				return null;

			return Ret.ToArray();
		}

		public static CodeString[] GetParamList(CompilerState State, CodeString Params, int Count = -1)
		{
			Params = Params.Trim();
			if (Params.Length == 0) return new CodeString[0];

			var Recognizer = State.Language.ParameterRecognizer;
			var Ret = Recognizer.SplitToParameters(State, Params);
			if (Ret == null) return null;

			if (Count != -1 && Count != Ret.Length)
			{
				State.Messages.Add(MessageId.ParamCount, Params);
				return null;
			}

			return Ret;
		}

		public static bool IsAcceptable(IdContainer Container, StringSlice String)
		{
			String = String.Trim();
			if (String.Length == 0) return false;

			var Lang = Container.State.Language;
            var Res = String.EndsWith(Lang.Root.NewLineRight, Lang.Root.NewLineRightSkip, new IdCharCheck(true));
			if (Res.Position != -1) return false;

            var Handlers = Lang.Root.GetObjectsStoreable<IFind2Handler>();
			for (var i = 0; i < Handlers.Length; i++)
				if (!Handlers[i].IsAcceptable(Container, String)) return false;

			return true;
		}

		public static bool IsAcceptable(IdContainer Container, CodeString String)
		{
			var Lang = Container.State.Language;
			String = String.Trim();

			if (!String.IsValid || String.Length == 0) return false;
            if (String.EndsWith(Lang.Root.Operators, Lang.Root.OnlyLeft, new IdCharCheck(true)).Position != -1)
				return false;

            var Handlers = Lang.Root.GetObjectsStoreable<IFind2Handler>();
			var StringRange = String.String;
			for (var i = 0; i < Handlers.Length; i++)
			{
				if (!Handlers[i].IsAcceptable(Container, StringRange))
					return false;
			}

			return true;
		}

		public static FindResult Find(LanguageNode Node, CompilerState State, StringSlice String)
		{
			return String.Find(Node.Operators, Node.Skip, true, new IdCharCheck(true), Node.SkippingHandlers);
		}

		public static IEnumerable<FindResult> EnumFind(LanguageNode Node, CompilerState State, StringSlice String)
		{
			return String.EnumFind(Node.Operators, Node.Skip, true, new IdCharCheck(true), Node.SkippingHandlers);
		}

		public static IEnumerable<FindResult> EnumFind2(LanguageNode Node, IdContainer Container, StringSlice String)
		{
			foreach (var Result in EnumFind(Node, Container.State, String))
			{
				if (IsAcceptable(Container, String.Substring(0, Result.Position).Trim()))
					yield return Result;
			}
		}

		public static FindResult Find2(LanguageNode Node, IdContainer Container, StringSlice String)
		{
			foreach (var e in EnumFind2(Node, Container, String))
				return e;

			return new FindResult(-1, -1, null);
		}

		public static ExpressionNode[] GetLeftRightNode(CodeString String, FindResult Result, PluginRoot Plugin)
		{
			var State = Plugin.State;
			var LeftStr = String.TrimmedSubstring(State, 0, Result.Position);
			var RightStr = String.TrimmedSubstring(State, Result.NextChar);
			if (!LeftStr.IsValid || !RightStr.IsValid) return null;

			var Left = Expressions.Recognize(LeftStr, Plugin, true);
			var Right = Expressions.Recognize(RightStr, Plugin, true);
			if (Left == null || Right == null) return null;

			return new ExpressionNode[] { Left, Right };
		}

		static CodeString CheckTrmSubStr(CompilerState State, CodeString String, int StrSize = 1, bool Back = false)
		{
			if (!Back) return String.TrimmedSubstring(State, StrSize);
			else return String.TrimmedSubstring(State, 0, String.Length - StrSize);
		}

		public static ExpressionNode OneParamOpNode(CodeString String, PluginRoot Plugin,
			Operator Op, int StrSize = 1)
		{
			var ps = CheckTrmSubStr(Plugin.State, String, StrSize);
			if (!ps.IsValid) return null;

			var Node = Expressions.Recognize(ps, Plugin, true);
			if (Node != null) return new OpExpressionNode(Op, new ExpressionNode[] {Node }, String);
			else return null;
		}
	}

	public static class Expressions
	{
		public static ExpressionNode GetSelfNode(ExpressionNode Node)
		{
			return IsSelfSpecified(Node) ? Node.Children[0] : null;
		}

		public static bool IsSelfSpecified(ExpressionNode Node)
		{
			if (Expressions.GetOperator(Node) == Operator.Member)
			{
				var Ch1Id = Expressions.GetIdentifier(Node.Children[1]);
				if (Ch1Id.RealId is Function && (Ch1Id.RealId.Flags & IdentifierFlags.Static) == 0)
					return true;
			}

			return false;
		}

		public static ExpressionNode Index(PluginRoot Plugin, ExpressionNode Node, ArrayIndices Indices, CodeString Code, bool End = false)
		{
			var Ch = new ExpressionNode[Indices.Indices.Length + 1];
			Ch[0] = Node;

			var RIndices = Indices.Indices;
			for (var i = 0; i < RIndices.Length; i++)
			{
				var ChNode = Plugin.NewNode(Constants.GetIntValue(Plugin.Container, RIndices[i], Code));
				if (ChNode == null) return null;

				Ch[i + 1] = ChNode;
			}

			Node = Plugin.NewNode(new OpExpressionNode(Operator.Index, Ch, Code));
			return Node == null || !End ? Node : Plugin.End(Node);
		}

		public static ExpressionNode Index(PluginRoot Plugin, Identifier Id, ArrayIndices Indices,
			CodeString Code, BeginEndMode BEMode = BeginEndMode.Begin)
		{
			if ((BEMode & BeginEndMode.Begin) != 0 && !Plugin.Begin())
				return null;

			var Node = Plugin.NewNode(new IdExpressionNode(Id, Code));
			if (Node == null) return null;

			return Index(Plugin, Node, Indices, Code, (BEMode & BeginEndMode.End) != 0);
		}

		public static ExpressionNode ChainedRelation(PluginRoot Plugin, IList<ExpressionNode> Nodes,
			IList<Operator> Operators, CodeString Code)
		{
			var LinkedNodes = new List<LinkedExprNode>();
			for (var i = 1; i < Nodes.Count - 1; i++)
				LinkedNodes.Add(new LinkedExprNode(Nodes[i]));

			var RetNodes = new List<ExpressionNode>();
			for (var i = 0; i < Operators.Count; i++)
			{
				var Op = Operators[i];
				var Ch = new ExpressionNode[]
				{
					i != 0 ? Plugin.NewNode(new LinkingNode(LinkedNodes[i - 1], Code)) : Nodes[i],
					i != Operators.Count - 1 ? Plugin.NewNode(new LinkingNode(LinkedNodes[i], Code)) : Nodes[i + 1],
				};

				if (Ch[0] == null || Ch[1] == null) return null;
				var NewNode = Plugin.NewNode(new OpExpressionNode(Op, Ch, Code));
				if (NewNode == null) return null;
				RetNodes.Add(NewNode);
			}

			while (RetNodes.Count > 1)
			{
				var Ch = new ExpressionNode[] { RetNodes[0], RetNodes[1] };
				var Node = (ExpressionNode)new OpExpressionNode(Operator.And, Ch, Code);

				if (LinkedNodes.Count > 0 && RetNodes.Count == 2)
					Node.LinkedNodes.Set(LinkedNodes);

				if ((Node = Plugin.NewNode(Node)) == null)
					return null;

				RetNodes.RemoveAt(0);
				RetNodes[0] = Node;
			}

			return RetNodes[0];
		}

		public static ExpressionNode CallToString(PluginRoot Plugin, ExpressionNode Node, CodeString Code)
		{
			var Member = Plugin.NewNode(new StrExpressionNode(new CodeString("ToString")));
			if (Member == null) return null;

			var FuncCh = new ExpressionNode[] { Node, Member };
			var Func = Plugin.NewNode(new OpExpressionNode(Operator.Member, FuncCh, Code));
			if (Func == null) return null;

			var CallCh = new ExpressionNode[] { Func };
			return Plugin.NewNode(new OpExpressionNode(Operator.Call, CallCh, Code));
		}

		public static ExpressionNode CallToStringSafe(PluginRoot Plugin, ExpressionNode Node, CodeString Code)
		{
			var Container = Plugin.Container;
			var Type = Node.Type.RealId as Type;

			if ((Type.TypeFlags & TypeFlags.ReferenceValue) == 0)
			{
				return CallToString(Plugin, Node, Code);
			}
			else
			{
				var LinkedNode = new LinkedExprNode(Node);
				var FuncCh0 = Plugin.NewNode(new LinkingNode(LinkedNode, Node.Code));
				if (FuncCh0 == null) return null;

				var CallNode = CallToString(Plugin, FuncCh0, Code);
				if (CallNode == null) return null;

				var CmpNull = Plugin.NewNode(Constants.GetNullValue(Container, Node.Code));
				var CmpSrc = Plugin.NewNode(new LinkingNode(LinkedNode, Node.Code));
				if (CmpNull == null || CmpSrc == null) return null;

				var CmpCh = new ExpressionNode[] { CmpSrc, CmpNull };
				var Cmp = Plugin.NewNode(new OpExpressionNode(Operator.Inequality, CmpCh, Node.Code));
				if (Cmp == null) return null;

				var CondElse = Plugin.NewNode(Constants.GetNullValue(Container, Node.Code));
				if (CondElse == null) return null;

				var CondCh = new ExpressionNode[] { Cmp, CallNode, CondElse };
				var Cond = new OpExpressionNode(Operator.Condition, CondCh, Node.Code);
				Cond.LinkedNodes.Add(LinkedNode);

				return Plugin.NewNode(Cond);
			}
		}

		public static ExpressionNode GetMember(PluginRoot Plugin, CodeString Code,
			ExpressionNode DstCh0, Identifier Member, bool End = false)
		{
			var DstCh1 = Plugin.NewNode(new IdExpressionNode(Member, Code));
			if (DstCh0 == null || DstCh1 == null) return null;

			var DstCh = new ExpressionNode[] { DstCh0, DstCh1 };
			var Node = Plugin.NewNode(new OpExpressionNode(Operator.Member, DstCh, Code));
			return Node == null || !End ? Node : Plugin.End(Node);
		}

		public static ExpressionNode GetMember(PluginRoot Plugin, CodeString Code, Identifier Id, Identifier Member, BeginEndMode BEMode = BeginEndMode.Begin)
		{
			if ((BEMode & BeginEndMode.Begin) != 0 && !Plugin.Begin())
				return null;

			var DstCh0 = Plugin.NewNode(new IdExpressionNode(Id, Code));
			return GetMember(Plugin, Code, DstCh0, Member, (BEMode & BeginEndMode.End) != 0);
		}

		public static ExpressionNode GetMember(PluginRoot Plugin, CodeString Code, Identifier Id, string Member, BeginEndMode BEMode = BeginEndMode.Begin)
		{
			var MemberId = Identifiers.GetMember(Plugin.State, Id.TypeOfSelf, Member, Code);
			if (MemberId == null) return null;

			return GetMember(Plugin, Code, Id, MemberId, BEMode);
		}

		public static ExpressionNode SetDefaultValue(PluginRoot Plugin, CodeString Code, Identifier Id, BeginEndMode Mode = BeginEndMode.Both)
		{
			return BeginEnd(Plugin, () =>
			{
				var Dst = Plugin.NewNode(new IdExpressionNode(Id, Code));
				var Src = Constants.GetDefaultValue(Plugin, Id, Code);
				if (Dst == null || Src == null) return null;

				var Ch = new ExpressionNode[] { Dst, Src };
				return Plugin.NewNode(new OpExpressionNode(Operator.Assignment, Ch, Code));
			}, Mode);
		}

		public static bool GetArrayLengths(CompilerState State, NodeGroup Group, List<int> List, int MaxDepth, int Depth = 0)
		{
			if (Depth >= MaxDepth)
			{
				State.Messages.Add(MessageId.NotExpected, Group.Code);
				return false;
			}

			var Count = Group.Children.Count;
			if (List.Count > Depth)
			{
				if (List[Depth] != Count)
				{
					State.Messages.Add(MessageId.ArrayInvalidLength, Group.Code);
					return false;
				}
			}
			else
			{
				List.Add(Count);
			}

			var NDepth = Depth + 1;
			for (var i = 0; i < Group.Children.Count; i++)
			{
				var Obj = Group.Children[i] as NodeGroup;
				if (Obj != null && !GetArrayLengths(State, Obj, List, MaxDepth, NDepth))
					return false;
			}

			return true;
		}

		public static int[] GetArrayLengths(CompilerState State, NodeGroup Group)
		{
			var List = new List<int>();
			if (!GetArrayLengths(State, Group, List, Group.MinDepth))
				return null;

			return List.ToArray();
		}

		public static bool IsLValue(ExpressionNode Node)
		{
			Node = Node.RealNode;

			var Op = Expressions.GetOperator(Node);
			if (Op == Operator.Assignment || Op == Operator.Index || Op == Operator.Member)
				return true;

			if (Op == Operator.Unknown && Node is IdExpressionNode)
				return true;

			return false;
		}

		private static ExpressionNode GetArrayDataSize(PluginRoot Plugin, 
			ExpressionNode[] Ch, int SizeOfValues, CodeString Code)
		{
			var Ret = Ch[0];
			ExpressionNode[] MulCh;

			for (var i = 1; i < Ch.Length; i++)
			{
				MulCh = new ExpressionNode[] { Ret, Ch[i] };
				Ret = Plugin.NewNode(new OpExpressionNode(Operator.Multiply, MulCh, Code));
				if (Ret == null) return null;
			}

			var SizeOfValuesNode = Plugin.NewNode(Constants.GetIntValue(Plugin.Container, SizeOfValues, Code));
			if (SizeOfValuesNode == null) return null;

			MulCh = new ExpressionNode[] { Ret, SizeOfValuesNode };
			return Plugin.NewNode(new OpExpressionNode(Operator.Multiply, MulCh, Code));
		}

		public static bool FinishParameters(PluginRoot Plugin, ExpressionNode[] Ch)
		{
			for (var i = 1; i < Ch.Length; i++)
			{
				Ch[i] = Plugin.FinishNode(Ch[i]);
				if (Ch[i] == null) return false;
			}

			return true;
		}

		public static ExpressionNode ConstructArray(PluginRoot Plugin, ExpressionNode Node)
		{
			if (Expressions.GetOperator(Node) != Operator.NewArray)
				throw new ApplicationException();

			return ConstructArray(Plugin, Node.Type, Node.Children, Node.Code);
		}

		public static ExpressionNode ConstructArray(PluginRoot Plugin, Identifier RefArrayType,
			int[] Lengths, CodeString Code, ExpressionNode InitialValue = null)
		{
			var Container = Plugin.Container;
			var LengthNodes = new ExpressionNode[Lengths.Length];
			for (var i = 0; i < Lengths.Length; i++)
			{
				LengthNodes[i] = Plugin.NewNode(Constants.GetIntValue(Container, Lengths[i], Code));
				if (LengthNodes[i] == null) return null;
			}

			return ConstructArray(Plugin, RefArrayType, LengthNodes, Code, InitialValue);
		}

		public static ExpressionNode ConstructArray(PluginRoot Plugin, Identifier RefArrayType, 
			ExpressionNode[] Lengths, CodeString Code, ExpressionNode InitialValue = null)
		{
			var State = Plugin.State;
			var Container = Plugin.Container;
			var RRefArrayType = RefArrayType.RealId as Type;
			var BaseType = RRefArrayType.Children[0];
			var RBaseType = BaseType.RealId as Type;

            var UINT_PTR = Container.GlobalContainer.CommonIds.UIntPtr;
            var ArrayClass = Identifiers.GetByFullNameFast<ClassType>(State, "System.Array");
			if (ArrayClass == null) return null;

			var DimensionCh = new ExpressionNode[Lengths.Length];
			for (var i = 0; i < Lengths.Length; i++)
			{
				DimensionCh[i] = Lengths[i];
				if (!(DimensionCh[i].Type.IsEquivalent(UINT_PTR)))
				{
                    DimensionCh[i] = Expressions.Convert(DimensionCh[i], UINT_PTR, Plugin);
					if (DimensionCh[i] == null) return null;
				}
			}

			var ArrayTypeNode = Plugin.NewNode(new IdExpressionNode(ArrayClass, Code));
			var BaseTypeNode = Plugin.NewNode(new DataPointerNode(Code, RefArrayType));
			var Dimensions = Plugin.NewNode(new OpExpressionNode(Operator.Array, DimensionCh, Code));
			var ItemSize = Plugin.NewNode(Constants.GetUIntValue(Container, (uint)RBaseType.Size, Code));
			if (ArrayTypeNode == null || BaseTypeNode == null || Dimensions == null || ItemSize == null)
				return null;

			ExpressionNode[] Ch;
			if (InitialValue == null) 
				Ch = new ExpressionNode[] { ArrayTypeNode, BaseTypeNode, Dimensions, ItemSize };
			else Ch = new ExpressionNode[] { ArrayTypeNode, BaseTypeNode, Dimensions, ItemSize, InitialValue };

			var Node = Plugin.NewNode(new OpExpressionNode(Operator.NewObject, Ch, Code));
			return Node == null ? null : Reinterpret(Node, RefArrayType, Plugin);
		}

		public static bool CheckNodeMultipleUsage(ExpressionNode Node)
		{
			if (!Node.CheckNodes(x => x != Node, false)) return false;
			return Node.CheckChildren(x => CheckNodeMultipleUsage(x));
		}

		public static bool CheckLinkedNodes(ExpressionNode Node, List<LinkedExprNode> LinkedNodes = null)
		{
			if (LinkedNodes == null)
				LinkedNodes = new List<LinkedExprNode>();

			for (var i = 0; i < Node.LinkedNodes.Count; i++)
				LinkedNodes.Add(Node.LinkedNodes[i]);

			var LNode = Node as LinkingNode;
			if (LNode != null && !LinkedNodes.Contains(LNode.LinkedNode))
				return false;

			if (!Node.CheckChildren(x => CheckLinkedNodes(x, LinkedNodes)))
				return false;

			for (var i = 0; i < Node.LinkedNodes.Count; i++)
				LinkedNodes.Remove(Node.LinkedNodes[i]);

			return true;
		}

		public static ExpressionNode[] GetAllMember(PluginRoot Plugin, ExpressionNode Node, out LinkedExprNode LinkedNode)
		{
			var Type = Node.Type.UnderlyingClassOrRealId as StructuredType;
			if (Type == null) throw new ApplicationException();

			var Members = Type.StructuredScope.IdentifierList;
			LinkedNode = new LinkedExprNode(Node);
			var Ret = new ExpressionNode[Members.Count];

			for (var i = 0; i < Members.Count; i++)
			{
				var Ch = new ExpressionNode[]
				{
					Plugin.NewNode(new LinkingNode(LinkedNode, Node.Code)),
					Plugin.NewNode(new IdExpressionNode(Members[i], Node.Code)),
				};

				if (Ch[0] == null || Ch[1] == null)
					return null;

				Ret[i] = Plugin.NewNode(new OpExpressionNode(Operator.Member, Ch, Node.Code));
				if (Ret[i] == null) return null;
			}

			return Ret;
		}

		public static Identifier GetTupleMemberType(ExpressionNode Node, int Index)
		{
			if (Index == -1)
				return Node.Type;

			if (Expressions.GetOperator(Node) == Operator.Tuple)
			{
				return Node.Children[Index].Type;
			}
			else
			{
				var Type = Node.Type.RealId as TupleType;
				var Members = Type.StructuredScope.IdentifierList;
				return Members[Index].Children[0];
			}
		}

		public static ExpressionNode GetTupleMember(PluginRoot Plugin, ref ExpressionNode Node, int Index, out LinkedExprNode LinkedNode)
		{
			LinkedNode = null;
			if (Index == -1)
				return Node;

			if (Expressions.GetOperator(Node) == Operator.Tuple)
			{
				return Node.Children[Index];
			}
			else
			{
				var Members = GetAllMember(Plugin, Node, out LinkedNode);
				if (Members == null) return null;

				Node = Plugin.NewNode(new OpExpressionNode(Operator.Tuple, Members, Node.Code));
				return Node == null ? null : Members[Index];
			}
		}

		public static void ProcessTuple(ExpressionNode Node, Action<ExpressionNode> Func)
		{
			if (Expressions.GetOperator(Node) == Operator.Tuple)
			{
				for (var i = 0; i < Node.Children.Length; i++)
					Func(Node.Children[i]);
			}
			else
			{
				Func(Node);
			}
		}

		public static bool ProcessTuple(ExpressionNode Node, Predicate<ExpressionNode> Func)
		{
			if (Expressions.GetOperator(Node) == Operator.Tuple)
			{
				var Ch = Node.Children;
				for (var i = 0; i < Ch.Length; i++)
					if (!Func(Ch[i])) return false;
			}
			else
			{
				if (!Func(Node)) return false;
			}

			return true;
		}

		public static bool ProcessTuple(ExpressionNode Node, Func<ExpressionNode, int, bool> Func)
		{
			if (Expressions.GetOperator(Node) == Operator.Tuple)
			{
				var Ch = Node.Children;
				for (var i = 0; i < Ch.Length; i++)
					if (!Func(Ch[i], i)) return false;
			}
			else
			{
				if (!Func(Node, -1)) return false;
			}

			return true;
		}

		public static PluginResult ProcessTuple(PluginRoot Plugin, ref ExpressionNode Node, 
			Func<ExpressionNode, int, ExpressionNode> Func)
		{
			if (Expressions.GetOperator(Node) == Operator.Tuple)
			{
				var Ch = Node.Children;
				var NewCreated = false;

				for (var i = 0; i < Ch.Length; i++)
				{
					var OldNode = Ch[i];
					Ch[i] = Func(OldNode, i);

					if (Ch[i] == null) return PluginResult.Failed;
					if (Ch[i] != OldNode) NewCreated = true;
				}

				if (NewCreated)
				{
					Node = Plugin.NewNode(Node);
					return Node == null ? PluginResult.Failed : PluginResult.Ready;
				}
			}
			else
			{
				var OldNode = Node;
				Node = Func(OldNode, -1);

				if (Node == null) return PluginResult.Failed;
				if (Node != OldNode) return PluginResult.Ready;
			}

			return PluginResult.Succeeded;
		}

		public static ExpressionNode CreateReference(IdContainer Container, Identifier Id,
			PluginRoot Plugin, CodeString Code, bool EnableMessages = true)
		{
			var Node = Plugin.NewNode(new IdExpressionNode(Id, Code));
			if (Node is IdExpressionNode)
			{
				var IdNode = Node as IdExpressionNode;
				if (IdNode.Identifier.IsInstanceIdentifier)
				{
					var MemVar = IdNode.Identifier as MemberVariable;
					var FS = Container.FunctionScope;
					var Self = FS != null ? FS.SelfVariable : null;

					var StructuredScope = IdNode.Identifier.Container.RealContainer as StructuredScope;
					if (Self != null && Self.Container.StructuredScope == StructuredScope)
					{
						var SelfNode = Plugin.NewNode(new IdExpressionNode(Self, Code));
						if (SelfNode == null) return null;

						var Ch = new ExpressionNode[] { SelfNode, IdNode };
						return Plugin.NewNode(new OpExpressionNode(Operator.Member, Ch, Code));
					}
					else
					{
						if (EnableMessages) 
							Plugin.State.Messages.Add(MessageId.NonStatic, Code);

						return null;
					}
				}
			}

			return Node;
		}

		public static ExpressionNode SetValue(ExpressionNode Destination, ExpressionNode Value,
			PluginRoot Plugin, CodeString Code = new CodeString(), bool End = false)
		{
			var Ch = new ExpressionNode[]
			{
				Destination,
				Value,
			};

			var Ret = Plugin.NewNode(new OpExpressionNode(Operator.Assignment, Ch, Code));

			if (End && Ret != null)
			{
				Ret = Plugin.End(Ret);
				if (Ret == null) return null;
			}

			return Ret;
		}

		public static ExpressionNode SetValue(Identifier Variable, ExpressionNode Value,
			PluginRoot Plugin, CodeString Code = new CodeString(), bool End = false)
		{
			var Destination = Plugin.NewNode(new IdExpressionNode(Variable, Code));
			if (Destination == null) return null;

			return SetValue(Destination, Value, Plugin, Code, End);
		}

		public static ExpressionNode SetValue(Identifier Self, Identifier Member, ExpressionNode Value,
			PluginRoot Plugin, CodeString Code = new CodeString(), bool End = false)
		{
			var Dst = GetMember(Plugin, Code, Self, Member, BeginEndMode.None);
			if (Dst == null) return null;

			return SetValue(Dst, Value, Plugin, Code, End);
		}

		public static ExpressionNode SetValue(Identifier Self, CodeString Member, ExpressionNode Value,
			PluginRoot Plugin, CodeString Code = new CodeString(), bool End = false)
		{
			var MemberId = Identifiers.GetMember(Plugin.State, Self.TypeOfSelf, Member);
			if (MemberId == null) return null;

			return SetValue(Self, MemberId, Value, Plugin, Code, End);
		}

		public static ExpressionNode SetValue(Identifier Self, string Member, ExpressionNode Value,
			PluginRoot Plugin, CodeString Code = new CodeString(), bool End = false)
		{
			var MemberId = Identifiers.GetMember(Plugin.State, Self.TypeOfSelf, Member, Code);
			if (MemberId == null) return null;

			return SetValue(Self, MemberId, Value, Plugin, Code, End);
		}

		public static ExpressionNode SetValue(Identifier Self, ArrayIndices Indices, ExpressionNode Value,
			PluginRoot Plugin, CodeString Code = new CodeString(), bool End = false)
		{
			var Dst = Index(Plugin, Self, Indices, Code, BeginEndMode.None);
			if (Dst == null) return null;

			return SetValue(Dst, Value, Plugin, Code, End);
		}

		public static ExpressionNode Convert(ExpressionNode Node, Identifier To, PluginRoot Plugin, CodeString Code = new CodeString())
		{
			var TypeNode = Plugin.NewNode(new IdExpressionNode(To, Code));
			if (TypeNode == null) return null;

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

		public static ExpressionNode Reinterpret(ExpressionNode Node, Identifier To, PluginRoot Plugin, CodeString Code = new CodeString())
		{
			var TypeNode = Plugin.NewNode(new IdExpressionNode(To, Code));
			if (TypeNode == null) return null;

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

		public static ExpressionNode Indirection(PluginRoot Plugin, ExpressionNode Node, CodeString Code)
		{
			var Zero = Plugin.NewNode(Constants.GetIntValue(Plugin.Container, 0, Code, true));
			if (Zero == null) return null;

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

		public static ExpressionNode GetAddress(PluginRoot Plugin, ExpressionNode Node, CodeString Code)
		{
			var Zero = Plugin.NewNode(Constants.GetIntValue(Plugin.Container, 0, Code, true));
			if (Zero == null) return null;

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

		public static Identifier GetIdentifier(ExpressionNode Node)
		{
			var IdNode = Node as IdExpressionNode;
			return IdNode != null ? IdNode.Identifier : null;
		}

		public static Identifier GetMemberIdentifier(ExpressionNode Node)
		{
			if (Node is IdExpressionNode)
			{
				var IdNode = Node as IdExpressionNode;
				return IdNode.Identifier;
			}
			else if (Node is OpExpressionNode)
			{
				var OpNode = Node as OpExpressionNode;
				var Op = OpNode.Operator;
				var Ch = OpNode.Children;

				if (Op != Operator.Member) return null;
				else return GetMemberIdentifier(Ch[1]);
			}
			else
			{
				return null;
			}
		}

		public static Operator GetOperator(ExpressionNode Node)
		{
			var OpNode = Node as OpExpressionNode;
			return OpNode != null ? OpNode.Operator : Operator.Unknown;
		}

		public static OverloadSelectionData GetOperatorSelectData(ExpressionNode[] Children)
		{
			var Ret = new OverloadSelectionData();
			Ret.Unnamed = new List<Identifier>();
			Ret.Specified = true;

			for (var i = 0; i < Children.Length; i++)
				Ret.Unnamed.Add(Children[i].Type);

			return Ret;
		}

		public static OverloadSelectionData GetOverloadSelectData(ExpressionNode[] Children)
		{
			var Ret = new OverloadSelectionData();
			Ret.Specified = true;

			for (var i = 1; i < Children.Length; i++)
			{
				if (Children[i] is NamedParameterNode)
				{
					var Node = Children[i] as NamedParameterNode;
					if (Ret.Named == null)
						Ret.Named = new Dictionary<string, Identifier>();

					Ret.Named.Add(Node.Name.ToString(), Node.Children[0].Type);
				}
				else
				{
					if (Ret.Unnamed == null)
						Ret.Unnamed = new List<Identifier>();

					Ret.Unnamed.Add(Children[i].Type);
				}
			}

			return Ret;
		}

		public static NodeGroup GetGroups(PluginRoot Plugin, CodeString Code)
		{
			var Rec = Plugin.State.Language.GroupRecognizer;
			return Rec.GetGroups(Plugin, Code);
		}

		public static ExpressionNode Increase(PluginRoot Plugin, ExpressionNode Src, ExpressionNode Val,
			CodeString Code, Operator Op = Operator.Add, bool End = true)
		{
			var Linked = new LinkedExprNode(Src);
			var Dst = Plugin.NewNode(new LinkingNode(Linked, Code));
			Src = Plugin.NewNode(new LinkingNode(Linked, Code));
			if (Dst == null || Src == null) return null;

			var Ch = new ExpressionNode[] { Src, Val };
			var AddNode = Plugin.NewNode(new OpExpressionNode(Op, Ch, Code));
			if (AddNode == null) return null;

			var RetVal = new OpExpressionNode(Operator.Assignment, Ch, Code);
			RetVal.Children = new ExpressionNode[] { Dst, AddNode };
			RetVal.LinkedNodes.Add(Linked);

			var Loop = Plugin.NewNode(RetVal);
			if (Loop == null) return null;

			if (End) return Plugin.End(Loop);
			else return Loop;
		}

		public static ExpressionNode Increase(PluginRoot Plugin, ExpressionNode Src, int Val,
			CodeString Code, Operator Op = Operator.Add, bool End = true)
		{
			var ValNode = Plugin.NewNode(Constants.GetIntValue(Plugin.Container, Val, Code, true));
			if (ValNode == null) return null;

			return Increase(Plugin, Src, ValNode, Code, Op, End);
		}

		public static ExpressionNode Increase(PluginRoot Plugin, Identifier Id, ExpressionNode Val,
			CodeString Code, Operator Op = Operator.Add, bool End = true)
		{
			var Src = Plugin.NewNode(new IdExpressionNode(Id, Code));
			if (Src == null) return null;

			return Increase(Plugin, Src, Val, Code, Op, End);
		}

		public static ExpressionNode Increase(PluginRoot Plugin, Identifier Id, int Val,
			CodeString Code, Operator Op = Operator.Add, BeginEndMode BEMode = BeginEndMode.Both)
		{
			if ((BEMode & BeginEndMode.Begin) != 0 && !Plugin.Begin()) return null;
			var ValNode = Plugin.NewNode(Constants.GetIntValue(Plugin.Container, Val, Code, true));
			if (ValNode == null) return null;

			return Increase(Plugin, Id, ValNode, Code, Op, (BEMode & BeginEndMode.End) != 0);
		}

		public static ExpressionNode Zero(PluginRoot Plugin, Identifier Id, CodeString Code)
		{
			if (!Plugin.Begin()) return null;
			var Zero = Plugin.NewNode(new ConstExpressionNode(Id.TypeOfSelf, new IntegerValue(0), Code));
			var Dst = Plugin.NewNode(new IdExpressionNode(Id, Code));
			if (Zero == null || Dst == null) return null;

			var Ch = new ExpressionNode[] { Dst, Zero };
			var Assignment = Plugin.NewNode(new OpExpressionNode(Operator.Assignment, Ch, Code));
			if (Assignment == null) return null;
			
			return Plugin.End(Assignment);
		}

		public static ExpressionNode ExtractTupleOp(ExpressionNode Node, PluginRoot Plugin, ExtractTupleOpFunc Func, bool[] AlwaysLink = null)
		{
			var DstType = Node.Type.RealId as TupleType;
			var LinkedNodes = new LinkedExprNode[Node.Children.Length];

			for (var i = 0; i < Node.Children.Length; i++)
				if (!(Node.Children[i].Type.RealId is TypeOfType))
				{
					var OpCh = Node.Children[i] as OpExpressionNode;
					if (OpCh == null || OpCh.Operator != Operator.Tuple || (AlwaysLink != null && AlwaysLink[i]))
						LinkedNodes[i] = new LinkedExprNode(Node.Children[i]);
				}

			var DstMembers = DstType.StructuredScope.IdentifierList;
			var NewCh = new ExpressionNode[DstMembers.Count];

			for (var i = 0; i < DstMembers.Count; i++)
			{
				var Member = DstMembers[i] as MemberVariable;
				var Args = new ExpressionNode[Node.Children.Length];

				for (var j = 0; j < Node.Children.Length; j++)
				{
					var Ch = Node.Children[j];
					if (Ch.Type.RealId is TypeOfType)
					{
						Args[j] = ExtractTupleChild(Plugin, Ch, i, Node.Code);
						if (Args[j] == null) return null;
					}
					else if (LinkedNodes[j] != null)
					{
						var Linking = Plugin.NewNode(new LinkingNode(LinkedNodes[j], Node.Code));
						if (Linking == null || Plugin.FinishNode(ref Linking) == PluginResult.Failed)
							return null;

						Args[j] = ExtractTupleChild(Plugin, Linking, i, Node.Code);
						if (Args[j] == null) return null;
					}
					else
					{
						Args[j] = Ch.Children[i];
					}
				}

				NewCh[i] = Func(i, Args);
				if (NewCh[i] == null) return null;
			}

			var NewNode = new OpExpressionNode(Operator.Tuple, NewCh, Node.Code);
			NewNode.LinkedNodes.AddRange(Node.LinkedNodes);
			if (LinkedNodes != null) NewNode.LinkedNodes.AddRange(LinkedNodes.Where(x => x != null));

			for (var i = 0; i < Node.Children.Length; i++)
			{
				if (LinkedNodes[i] == null)
					NewNode.LinkedNodes.AddRange(Node.Children[i].LinkedNodes);
			}

			NewNode.Type = Node.Type;
			return Plugin.NewNode(NewNode);
		}

		public static ExpressionNode ExtractTupleChild(PluginRoot Plugin, ExpressionNode Node, int Index, CodeString Code)
		{
			if (Node.Type.RealId is TypeOfType)
			{
				var SrcType = Expressions.GetIdentifier(Node).RealId as TupleType;
				var SrcMembers = SrcType.StructuredScope.IdentifierList;
				return Plugin.NewNode(new IdExpressionNode(SrcMembers[Index], Code));
			}
			else
			{
				var SrcType = Node.Type.RealId as TupleType;
				var SrcMembers = SrcType.StructuredScope.IdentifierList;
				return GetMember(Plugin, Code, Node, SrcMembers[Index]);
			}
		}
		
		public static bool IsDouble(int Size)
		{
			bool Double;
			if (Size == 8) Double = true;
			else if (Size == 4) Double = false;
			else throw new ApplicationException();
			return Double;
		}

		public static bool IsDouble(Type Type)
		{
			return IsDouble(Type.Size);
		}

		public static bool IsDouble(ExpressionNode Node)
		{
			return IsDouble(Node.Type.RealId as Type);
		}

		public static ExpressionNode CreateConstNode(CodeString Code, 
			ConstValue Data, Type Type, PluginRoot Plugin = null)
		{
			var Ret = new ConstExpressionNode(Type, Data, Code);
			if (Plugin == null) return Ret;
			else return Plugin.NewNode(Ret);
		}

		public static ExpressionNode CallIndex(CodeString Code, PluginRoot Plugin,
			Operator Op, CodeString FuncName, params ExpressionNode[] Ch)
		{
			var Func = Recognize(FuncName, Plugin, false);
			if (Func == null) return null;

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

			return Plugin.NewNode(new OpExpressionNode(Op, NewCh, Code));
		}

		public static ExpressionNode Call(CodeString Code, PluginRoot Plugin, Function Function, params ExpressionNode[] Ch)
		{
			var Func = Plugin.NewNode(new IdExpressionNode(Function, Code));
			if (Func == null) return null;

			var NewCh = new ExpressionNode[Ch.Length + 1];
			NewCh[0] = Func;
			Ch.CopyTo(NewCh, 1);
			return Plugin.NewNode(new OpExpressionNode(Operator.Call, NewCh, Code));
		}

		public static ExpressionNode CreateExpression(CodeString Code, PluginRoot Plugin, BeginEndMode Mode = BeginEndMode.Both)
		{
			return BeginEnd(Plugin, () => Recognize(Code, Plugin, false), Mode);
		}

		public static ExpressionNode CreateExpression_RetValLess(CodeString Code, PluginRoot Plugin, BeginEndMode Mode = BeginEndMode.Both)
		{
			var Rec = Plugin.State.Language.RetValLessRecognizer;
			if (Rec == null) return CreateExpression(Code, Plugin, Mode);

			Code = Code.Trim();
			return BeginEnd(Plugin, () => Rec.Recognize(Code, Plugin), Mode); 
		}

		public static ExpressionNode BeginEnd(PluginRoot Plugin, Func<ExpressionNode> Func, BeginEndMode Mode = BeginEndMode.Both)
		{
			if ((Mode & BeginEndMode.Begin) != 0 && !Plugin.Begin()) 
				return null;

			var Ret = Func();
			if ((Mode & BeginEndMode.End) != 0 && Ret != null) 
				Ret = Plugin.End(Ret);

			return Ret;
		}

		public static ExpressionNode[] Recognize(IList<CodeString> Code, PluginRoot Plugin)
		{
			var RetValue = true;
			var Ret = new ExpressionNode[Code.Count];
			
			for (var i = 0; i < Code.Count; i++)
			{
				Ret[i] = Recognize(Code[i], Plugin);
				if (Ret[i] == null) RetValue = false;
			}

			return RetValue ? Ret : null;
		}

		public static ExpressionNode Recognize(CodeString Code, PluginRoot Plugin,
			bool Trimmed = false, IList<IExprRecognizer> Recognizers = null)
		{
			if (!Trimmed) Code = Code.Trim();
#if DEBUG
			else if (Code.LeftWhiteSpaces != 0 || Code.RightWhiteSpaces != 0)
				throw new ApplicationException("Not Trimmed");

			if (!Code.IsValid || Code.Length == 0)
				throw new ApplicationException("Deficient");
#endif
			if (Recognizers == null)
				Recognizers = Plugin.State.Language.ExprRecognizers;

			ExpressionNode Out;
			var Res = Recognize(Code, Plugin, Recognizers, out Out);
			if (Res != SimpleRecResult.Unknown)
				return Res == SimpleRecResult.Succeeded ? Out : null;

			Plugin.State.Messages.Add(MessageId.UnknownOp, Code);
			return null;
		}

		public static SimpleRecResult Recognize(CodeString Code, PluginRoot Plugin,
			IList<IExprRecognizer> Recognizers, out ExpressionNode Out)
		{
			Out = null;
			for (var i = 0; i < Recognizers.Count; i++)
			{
				var Res = Recognizers[i].Recognize(Code, Plugin, ref Out);
				if (Res != ExprRecResult.Unknown)
				{
					if (Res == ExprRecResult.Failed)
					{
						Out = null;
						return SimpleRecResult.Failed;
					}
					
					if (Out == null)
						throw new ApplicationException("Recognized expression name cannot be null");

					if (Res == ExprRecResult.Succeeded && (Out = Plugin.NewNode(Out)) == null)
						 return SimpleRecResult.Failed;

					return SimpleRecResult.Succeeded;
				}
			}

			return SimpleRecResult.Unknown;
		}
	}
}

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