Click here to Skip to main content
15,879,474 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.7K   282   14  
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 System.Text;
using Bird.Languages.Bird;

namespace Bird.Recognizers
{
	public class IsAsToRecognizer : LanguageNode, IExprRecognizer
	{
		public IsAsToRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "is", "as", "to" };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Out)
		{
			var Result = RecognizerHelper.Find(this, Plugin.State, Code.String);
			if (Result.Position != -1)
			{
				var State = Plugin.State;
				var LeftStr = Code.TrimmedSubstring(State, 0, Result.Position);
				var RightStr = Code.TrimmedSubstring(State, Result.NextChar);
				if (!LeftStr.IsValid || !RightStr.IsValid) return ExprRecResult.Failed;

				var TypeOptions = GetIdOptions.DefaultForType;
				var Type = Identifiers.Recognize(Plugin.Container, RightStr);
				if (Type == null) return ExprRecResult.Failed;

				var Left = Expressions.Recognize(LeftStr, Plugin, true);
				var Right = Plugin.NewNode(new IdExpressionNode(Type, RightStr));
				if (Left == null || Right == null) return ExprRecResult.Failed;

				Operator Op;
				if (Result.Index == 0) Op = Operator.Is;
				else if (Result.Index == 1) Op = Operator.As;
				else if (Result.Index == 2) Op = Operator.Cast;
				else throw new ApplicationException();

				var Ch = new ExpressionNode[] { Left, Right };
				Out = new OpExpressionNode(Op, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class CastRecognizer : LanguageNode, IExprRecognizer, IFind2Handler
	{
		public CastRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "(" };
		}

		public bool IsCastString(CompilerState State, StringSlice String)
		{
			if (String.StartsWith(Operators, Skip).Position != -1)
			{
				var ZPos = String.GetBracketPos(false, SkippingHandlers);
				var Right = String.Substring(ZPos + 1).Trim();
				if (ZPos == -1 || Right.Length == 0) return false;

				var Lang = State.Language;
                var Res = Right.StartsWith(Lang.Root.NewLineLeft, Lang.Root.OnlyRight, new IdCharCheck(true));
				return Res.Position == -1 || (Right.Length > 0 && Right[0] == '(');
			}

			return false;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (IsCastString(Plugin.State, Code.String))
			{
				var State = Plugin.State;
				var Container = Plugin.Container;
				var Pos = Code.GetBracketPos(State);
				if (Pos == -1) return ExprRecResult.Failed;

				var TypeName = Code.TrimmedSubstring(State, 1, Pos - 1);
				var ChildStr = Code.TrimmedSubstring(State, Pos + 1);
				if (!TypeName.IsValid || !ChildStr.IsValid) return ExprRecResult.Failed;

				var Type = Container.RecognizeIdentifier(TypeName, GetIdOptions.DefaultForType);
                if (Type == null) return ExprRecResult.Failed;

				var Child = Expressions.Recognize(ChildStr, Plugin, true);
                var TypeNode = Plugin.NewNode(new IdExpressionNode(Type, TypeName));
                if (Child == null || TypeNode == null) return ExprRecResult.Failed;

                var Ch = new ExpressionNode[] { Child, TypeNode };
                Ret = new OpExpressionNode(Operator.Cast, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}

		public bool IsAcceptable(IdContainer Container, StringSlice String)
		{
			var BracketPos = String.Length - 1;
			if (BracketPos > 0 && String[BracketPos] == ')')
			{
				var Handlers = Container.State.Language.GlobalHandlers;
				var ZPos = String.GetBracketPos(true, Handlers);
				if (ZPos == -1) return true;

				var Left = String.Substring(0, ZPos);
				if (RecognizerHelper.IsAcceptable(Container, Left))
					return true;

				var SubStr = new CodeString(String.Substring(ZPos + 1, BracketPos - ZPos - 1));
				var Options = GetIdOptions.DefaultForType;
				Options.EnableMessages = false;
				return Container.RecognizeIdentifier(SubStr, Options) == null;
			}

			return true;
		}
	}

	public class RangeRecognizer : LanguageNode, IExprRecognizer
	{
		public RangeRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "...", ".." };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Out)
		{
			var Result = RecognizerHelper.Find(this, Plugin.State, Code.String);
			if (Result.Position != -1)
			{
				var Ch = RecognizerHelper.GetLeftRightNode(Code, Result, Plugin);
				if (Ch == null) return ExprRecResult.Failed;

				Operator Op;
				if (Result.Index == 0) Op = Operator.RangeTo;
				else if (Result.Index == 1) Op = Operator.RangeUntil;
				else throw new ApplicationException();

				Out = new OpExpressionNode(Op, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class VarDeclRecignizer : LanguageNode, IExprRecognizer
	{
		public VarDeclRecignizer(LanguageNode Parent)
			: base(Parent)
		{
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Out)
		{
			var State = Plugin.State;
			var AutoType = State.GlobalContainer.CommonIds.Auto;

			if (Code.StartsWith(AutoType.Name.ToString(), new IdCharCheck(true)))
			{
				var VarDeclRec = State.Language.VarDeclRecognizer;
				var Decls = new VarDeclarationList();
				if (!VarDeclRec.Recognize(Plugin.Container, Code, true, Decls))
					return ExprRecResult.Failed;

				var Vars = Decls.ToVariables(Plugin, BeginEndMode.None,
					VarDeclConvMode.Assignment, true, true, true);

				if (Vars == null || Vars.Contains(null)) 
					return ExprRecResult.Failed;

                if (Vars.Length == 1)
				{
					Out = new IdExpressionNode(Vars[0], Decls[0].Declaration);
					return ExprRecResult.Succeeded;
				}

                var RetCh = new ExpressionNode[Vars.Length];
				var HaveInitVals = true;
                for (var i = 0; i < Vars.Length; i++)
				{
					var e = Vars[i];
					if (i == 0)
					{
						HaveInitVals = e.InitValue != null;
					}
					else if ((e.InitValue != null) != HaveInitVals)
					{
						State.Messages.Add(MessageId.ExprVarDeclInitVal, e.Name);
						return ExprRecResult.Failed;
					}

					var Node = e.InitValue;
					if (Node == null)
					{
						Node = Plugin.NewNode(new IdExpressionNode(e, Decls[i].Declaration));
						if (Node == null) return ExprRecResult.Failed;
					}

					RetCh[i] = Node;
				}

				Out = new OpExpressionNode(Operator.Tuple, RetCh, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class RefRecognizer : LanguageNode, IExprRecognizer
	{
		public RefRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			NewLineRight = Operators = new string[] { "unsafe_ref", "ref", "out" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var Result = Code.StartsWith(Operators, Skip, IdCharCheck: new IdCharCheck(true));
			if (Result.Index != -1)
			{
				var SubCode = Code.TrimmedSubstring(Plugin.State, Result.String.Length);
				if (!SubCode.IsValid) return ExprRecResult.Failed;

				var Child = Expressions.Recognize(SubCode, Plugin, true);
				if (Child == null) return ExprRecResult.Failed;

				Operator Op;
				if (Result.Index == 0) Op = Operator.Reference_Unsafe;
				else if (Result.Index == 1) Op = Operator.Reference_IdMustBeAssigned;
				else if (Result.Index == 2) Op = Operator.Reference_IdGetsAssigned;
				else throw new ApplicationException();

				var Ch = new ExpressionNode[] { Child };
				Ret = new OpExpressionNode(Op, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class BirdNewRecognizer : LanguageNode, IExprRecognizer
	{
		public CallRecognizer CallRecognizer;
		public bool EnableWithoutBracket = true;

		public BirdNewRecognizer(LanguageNode Parent)
			: base(Parent)
		{
		}

        public override void Init(LanguageInitData InitData)
		{
            CallRecognizer = Language.Root.GetObject<CallRecognizer>();
			base.Init(InitData);
		}

		public NodeGroup GetGroups(PluginRoot Plugin, CodeString Code, int DimensionCount)
		{
			var State = Plugin.State;
			var Container = Plugin.Container;
			var Ret = new NodeGroup(Code);

			var Result = BirdHelper.ForEachLine(State, Code, Line =>
			{
				var Rec = State.Language.ParameterRecognizer;
				var List = Rec.SplitToParameters(State, Line);
				if (List == null) return false;

				var LocalGroup = (NodeGroup)null;
				if (DimensionCount >= 2)
				{
					LocalGroup = new NodeGroup(Line);
					Ret.Children.Add(LocalGroup);
				}

				var RetValue = true;
				for (var i = 0; i < List.Length; i++)
				{
					var String = List[i];
					object Object;

					if (String.Length > 1 && String[0] == '(' && String[String.Length - 1] == ')')
					{
						var SubString = String.TrimmedSubstring(State, 1, String.Length - 2);
						if (!SubString.IsValid) { RetValue = false; continue; }

						var NewGroup = BracketGroupRecognizer.GetGroups(Plugin, SubString, '(', ')');
						if (NewGroup == null) { RetValue = false; continue; }

						if (NewGroup.MaxDepth + 1 == DimensionCount)
						{
							LocalGroup.Children.AddRange(NewGroup.Children);
							continue;
						}

						Object = NewGroup;
					}
					else
					{
						Object = Expressions.Recognize(String, Plugin, true);
						if (Object == null) { RetValue = false; continue; }
					}

					if (LocalGroup == null) Ret.Children.Add(Object);
					else LocalGroup.Children.Add(Object);
				}

				return RetValue;
			});

			return Result ? Ret : null;
		}

		public bool CheckGroups_DimensionsNotSpecified(PluginRoot Plugin,
			NodeGroup Group, ExpressionNode[] Ch, CodeString Code, int DimensionCount)
		{
			var State = Plugin.State;
			var Global = State.GlobalContainer;
			var Container = Plugin.Container;

			var Lengths = Expressions.GetArrayLengths(State, Group);
			if (Lengths == null) return false;

			if (DimensionCount != Lengths.Length)
			{
				State.Messages.Add(MessageId.ArrayInitializerLength, Code);
				return false;
			}

			var Succeeded = true;
			for (var i = 0; i < Lengths.Length; i++)
			{
				var Node = Plugin.NewNode(Constants.GetIntValue(Container, Lengths[i], Code));
				if (Node == null) { Succeeded = false; continue; }

				Ch[i + 1] = Node;
			}

			return Succeeded;
		}

		public bool CheckGroups_DimensionsSpecified(PluginRoot Plugin, 
			NodeGroup Group, ExpressionNode[] Ch, CodeString Code)
		{
			var State = Plugin.State;
			var Global = State.GlobalContainer;

			var Lengths = Expressions.GetArrayLengths(State, Group);
			if (Lengths == null) return false;

			if (Ch.Length - 1 != Lengths.Length)
			{
				State.Messages.Add(MessageId.ArrayInitializerLength, Code);
				return false;
			}

			var RetValue = true;
			for (var i = 0; i < Lengths.Length; i++)
			{
				var Node = Ch[i + 1];
				if (!Node.Type.IsEquivalent(Global.CommonIds.Int32))
				{
					var TypeMngrPlugin = Plugin.GetPlugin<TypeMngrPlugin>();
					if (TypeMngrPlugin == null)
					{
						State.Messages.Add(MessageId.ImplicitlyCast, Node.Code);
						RetValue = false;
						continue;
					}

					Node = TypeMngrPlugin.Convert(Node, Global.CommonIds.Int32, Node.Code);
					if (Node == null) { RetValue = false; continue; }

					Ch[i + 1] = Node;
				}

				var ConstNode = Node as ConstExpressionNode;
				if (ConstNode == null)
				{
					State.Messages.Add(MessageId.MustBeConst, Node.Code);
					RetValue = false;
					continue;
				}

				if (Lengths[i] != ConstNode.Integer)
				{
					State.Messages.Add(MessageId.ArrayInitializerLength, Node.Code);
					RetValue = false;
					continue;
				}
			}

			return RetValue;
		}

		private ExpressionNode CreateIndexNode(PluginRoot Plugin, Identifier Id, List<int> Indices, CodeString Code)
		{
			var Container = Plugin.Container;

			var Ch = new ExpressionNode[Indices.Count + 1];
			Ch[0] = Plugin.NewNode(new IdExpressionNode(Id, Code));
			if (Ch[0] == null) return null;

			for (var i = 0; i < Indices.Count; i++)
			{
				Ch[i + 1] = Plugin.NewNode(Constants.GetIntValue(Container, Indices[i], Code));
				if (Ch[i + 1] == null) return null;
			}

			return Plugin.NewNode(new OpExpressionNode(Operator.Index, Ch, Code));
		}

		public void CreateInitValue_ForArray(NodeGroup Group, List<ExpressionNode> Children, 
			List<ArrayIndices> Indices, List<int> CurrentIndices = null)
		{
			if (CurrentIndices == null)
				CurrentIndices = new List<int>();

			for (var i = 0; i < Group.Children.Count; i++)
			{
				CurrentIndices.Add(i);

				var Object = Group.Children[i];
				if (Object is ExpressionNode)
				{
					Children.Add(Object as ExpressionNode);
					Indices.Add(new ArrayIndices(CurrentIndices.ToArray()));
				}
				else if (Object is NodeGroup)
				{
					CreateInitValue_ForArray(Object as NodeGroup, Children, Indices, CurrentIndices);
				}
				else
				{
					throw new ApplicationException();
				}

				CurrentIndices.RemoveAt(CurrentIndices.Count - 1);
			}
		}

		public bool CreateInitValue_ForArray(PluginRoot Plugin, NodeGroup Group,
			ExpressionNode Node, CodeString Code)
		{
			var Children = new List<ExpressionNode>();
			var Indices = new List<ArrayIndices>();
			CreateInitValue_ForArray(Group, Children, Indices);

			var LNode = Plugin.NewNode(new ArrayInitNode(Children.ToArray(), Indices.ToArray(), Code));
			if (LNode == null) return false;

			Node.LinkedNodes.Add(new LinkedExprNode(LNode, LinkedNodeFlags.NotRemovable));
			return true;
		}

		public bool CreateInitValue_ForObject(PluginRoot Plugin, ExpressionNode Node, CodeString Code)
		{
			var State = Plugin.State;
			var Container = Plugin.Container;
			var SkippingHandlers = State.Language.GlobalHandlers;
			var Refs = new List<IdentifierReference>();
			var Nodes = new List<ExpressionNode>();

			var Result = BirdHelper.ForEachLine(State, Code, Line =>
			{
				var Rec = State.Language.ParameterRecognizer;
				var List = Rec.SplitToParameters(State, Line);
				if (List == null) return false;
				
				var RetValue = true;
				for (var i = 0; i < List.Length; i++)
				{
					var String = List[i];
					var Pos = String.Find('=', false, SkippingHandlers);
					if (Pos == -1) 
					{
						State.Messages.Add(MessageId.NotExpected, String);
						RetValue = false;
						continue;
					}
					
					var Left = String.TrimmedSubstring(State, 0, Pos);
					var Right = String.TrimmedSubstring(State, Pos + 1);
					if (!Left.IsValid || !Right.IsValid) { RetValue = false; continue; }

					if (!Left.IsValidIdentifierName)
					{
						State.Messages.Add(MessageId.NotValidName, Left);
						RetValue = false;
						continue;
					}

					var Value = Expressions.Recognize(Right, Plugin, true);
					if (Node == null) return false;

					Refs.Add(new IdentifierReference(Left));
					Nodes.Add(Value);
				}

				return RetValue;
			});

			var LNode = Plugin.NewNode(new ObjectInitNode(Refs.ToArray(), Nodes.ToArray(), Code));
			if (LNode == null) return false;

			Node.LinkedNodes.Add(new LinkedExprNode(LNode, LinkedNodeFlags.NotRemovable));
			return Result;
		}

		public int GetOnlyDimensions(CodeString Code)
		{
			var Ret = 1;
			for (var i = 0; i < Code.Length; i++)
			{
				var Char = Code[i];
				if (!char.IsWhiteSpace(Char) && Char != ',') return -1;
				else if (Char == ',') Ret++;
			}

			return Ret;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.StartsWith("new", new IdCharCheck(true)))
			{
				var State = Plugin.State;
				var Container = Plugin.Container;
				var Global = State.GlobalContainer;

				var EndingResult = State.Language.CommandInnerSeparator.Separate
					(State, Code, CommandInnerSeparatorFlags.InnerIsOptional);

				if (!EndingResult.Command.IsValid) return ExprRecResult.Failed;

				var SubCode = EndingResult.Command.Substring(3).Trim();
				var LChar = SubCode.Length == 0 ? '\0' : SubCode[SubCode.Length - 1];

				var Ch = (ExpressionNode[])null;
				var Op = Operator.Unknown;
				var StrParams = new CodeString();
				var DimensionCount = -1;
				var DimensionsSpecified = true;

				if (LChar == ']' || LChar == ')')
				{
					if (LChar == ']') Op = Operator.NewArray;
					else if (LChar == ')') Op = Operator.NewObject;
					else throw new ApplicationException();

					var ZPos = SubCode.GetBracketPos(State, Back: true);
					if (ZPos == -1) return ExprRecResult.Failed;

					StrParams = SubCode.Substring(ZPos + 1, SubCode.Length - ZPos - 2).Trim();
					SubCode = SubCode.Substring(0, ZPos).Trim();

					DimensionCount = GetOnlyDimensions(StrParams);
					if (Op == Operator.NewArray && DimensionCount != -1)
					{
						DimensionsSpecified = false;
						Ch = new ExpressionNode[DimensionCount + 1];
					}
					else
					{
						Ch = CallRecognizer.ProcessParameters(Plugin, new CodeString(), StrParams);
						if (Ch == null) return ExprRecResult.Failed;
					}

					if (SubCode.Length == 0)
					{
						var Auto = Container.GlobalContainer.CommonIds.Auto;
						Ch[0] = Plugin.NewNode(new IdExpressionNode(Auto, Code));
						if (Ch[0] == null) return ExprRecResult.Failed;
					}
					else
					{
						Ch[0] = Plugin.NewNode(new StrExpressionNode(SubCode));
						if (Ch[0] == null) return ExprRecResult.Failed;
					}
				}
				else if (SubCode.Length == 0)
				{
					if (!EnableWithoutBracket)
					{
						State.Messages.Add(MessageId.DeficientExpr, Code);
						return ExprRecResult.Failed;
					}

					var Auto = Container.GlobalContainer.CommonIds.Auto;
					Op = Operator.NewObject;

					Ch = new ExpressionNode[1];
					Ch[0] = Plugin.NewNode(new IdExpressionNode(Auto, Code));
					if (Ch[0] == null) return ExprRecResult.Failed;
				}
				else
				{
					if (!EnableWithoutBracket)
					{
						State.Messages.Add(MessageId.NotExpected, SubCode);
						return ExprRecResult.Failed;
					}

					Op = Operator.NewObject;
					Ch = new ExpressionNode[1];
					Ch[0] = Plugin.NewNode(new StrExpressionNode(SubCode));
					if (Ch[0] == null) return ExprRecResult.Failed;
				}

				Ret = new OpExpressionNode(Op, Ch, Code);

				if (EndingResult.Inner.IsValid)
				{
					if (Op == Operator.NewArray)
					{
						var Groups = GetGroups(Plugin, EndingResult.Inner, Ch.Length - 1);
						if (Groups == null) return ExprRecResult.Failed;

						if (DimensionsSpecified)
						{
							if (!CheckGroups_DimensionsSpecified(Plugin, Groups, Ch, Code))
								return ExprRecResult.Failed;
						}
						else
						{
							if (!CheckGroups_DimensionsNotSpecified(Plugin, Groups, Ch, Code, DimensionCount))
								return ExprRecResult.Failed;
						}

						if (!CreateInitValue_ForArray(Plugin, Groups, Ret, Code))
							return ExprRecResult.Failed;
					}
					else if (Op == Operator.NewObject)
					{
						if (!CreateInitValue_ForObject(Plugin, Ret, EndingResult.Inner))
							return ExprRecResult.Failed;
					}
					else
					{
						throw new ApplicationException();
					}
				}
				else if (Op == Operator.NewArray && !DimensionsSpecified)
				{
					State.Messages.Add(MessageId.ArrayLengthNotSpecified, StrParams);
					return ExprRecResult.Failed;
				}

				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class NewRecognizer : LanguageNode, IExprRecognizer
	{
		public CallRecognizer CallRecognizer;

		public NewRecognizer(LanguageNode Parent)
			: base(Parent)
		{
		}

        public override void Init(LanguageInitData InitData)
		{
            CallRecognizer = Language.Root.GetObject<CallRecognizer>();
			base.Init(InitData);
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.StartsWith("new", new IdCharCheck(true)))
			{
				var State = Plugin.State;
				var Container = Plugin.Container;

				var SubCode = Code.TrimmedSubstring(State, 3);
				if (!SubCode.IsValid) return ExprRecResult.Failed;

				var Len = SubCode.Length;
				var LChar = SubCode[Len - 1];

				var Ch = (ExpressionNode[])null;
				var Op = Operator.Unknown;
				if (LChar == ']' || LChar == ')')
				{
					if (LChar == ']') Op = Operator.NewArray;
					else if (LChar == ')') Op = Operator.NewObject;
					else throw new ApplicationException();

					var ZPos = SubCode.GetBracketPos(State, Back: true);
					if (ZPos == -1) return ExprRecResult.Failed;

					var StrParams = SubCode.Substring(ZPos + 1, Len - ZPos - 2).Trim();
					SubCode = SubCode.Substring(0, ZPos).Trim();

					Ch = CallRecognizer.ProcessParameters(Plugin, SubCode, StrParams);
					if (Ch == null) return ExprRecResult.Failed;
				}
				else
				{
					Ch = new ExpressionNode[] { Plugin.NewNode(new StrExpressionNode(SubCode)) };
					if (Ch[0] == null) return ExprRecResult.Failed;

					Op = Operator.NewObject;
				}

				Ret = new OpExpressionNode(Op, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class IfThenRecognizer : LanguageNode, IExprRecognizer
	{
		public string[] ThenStrs = new string[] { ":", "then" };
		public string[] ElseStrs = new string[] { "else" };

		public IfThenRecognizer(LanguageNode Parent)
			: base(Parent)
		{
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.StartsWith("if", new IdCharCheck(true)))
			{
				var State = Plugin.State;
				var Container = Plugin.Container;
				var SkippingHandler = State.Language.GlobalHandlers;

				FindResult Result;
				var SCode = Code.Substring(2);
				if (!SCode.IsValid || (Result = SCode.Find(ThenStrs, IdCharCheck: new IdCharCheck(true), Handlers: SkippingHandler)).Position == -1)
				{
					State.Messages.Add(MessageId.NeedThenElse, Code);
					return ExprRecResult.Failed;
				}

				var ConditionStr = SCode.TrimmedSubstring(State, 0, Result.Position);
				SCode = SCode.Substring(Result.NextChar);

				if (!SCode.IsValid || (Result = SCode.Find(ElseStrs, Handlers: SkippingHandler, IdCharCheck: new IdCharCheck(true))).Position == -1)
				{
					State.Messages.Add(MessageId.NeedThenElse, Code);
					return ExprRecResult.Failed;
				}

				var ThenStr = SCode.TrimmedSubstring(State, 0, Result.Position);
				var ElseStr = SCode.TrimmedSubstring(State, Result.NextChar);
				if (!ThenStr.IsValid || !ElseStr.IsValid || !ConditionStr.IsValid)
					return ExprRecResult.Failed;

				var Condition = Expressions.Recognize(ConditionStr, Plugin, true);
				var Then = Expressions.Recognize(ThenStr, Plugin, true);
				var Else = Expressions.Recognize(ElseStr, Plugin, true);

				if (Condition == null || Then == null || Else == null)
					return ExprRecResult.Failed;

				var Ch = new ExpressionNode[] {Condition, Then, Else };
				Ret = new OpExpressionNode(Operator.Condition, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class ConditionRecognizer : LanguageNode, IExprRecognizer
	{
		public ConditionRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "?", ":" };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var State = Plugin.State;
			var SkippingHandler = State.Language.GlobalHandlers;

			var Depth = 0;
			var Begin = new FindResult(-1, -1, null);
			var End = new FindResult(-1, -1, null);
			foreach (var e in Code.EnumFind(Operators, Skip, Handlers: SkippingHandler))
			{
				if (e.Index == 0)
				{
					if (Depth == 0) Begin = e;
					Depth++;
				}
				else if (e.Index == 1)
				{
					Depth--;
					if (Depth == 0) End = e;
				}
				else
				{
					throw new ApplicationException();
				}
			}

			if (Begin.Position != -1 && Begin.Index == 0 && End.Position != -1 && End.Index == 1)
			{
				var Left_Str = Code.TrimmedSubstring(State, 0, Begin.Position);
				var MidPos = Begin.Position + Begin.String.Length;
				var Mid_Str = Code.TrimmedSubstring(State, MidPos, End.Position - MidPos);
				var Right_Str = Code.TrimmedSubstring(State, End.Position + End.String.Length);

				if (!Left_Str.IsValid || !Mid_Str.IsValid || !Right_Str.IsValid)
					return ExprRecResult.Failed;

				var Left = Expressions.Recognize(Left_Str, Plugin, true);
				var Mid = Expressions.Recognize(Mid_Str, Plugin, true);
				var Right = Expressions.Recognize(Right_Str, Plugin, true);
				if (Left == null || Mid == null || Right == null)
					return ExprRecResult.Failed;

				var Ch = new ExpressionNode[] { Left, Mid, Right };
				Ret = new OpExpressionNode(Operator.Condition, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class AssignmentRecognizer : LanguageNode, IExprRecognizer
	{
		public AssignmentRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", "|=", "&=", "^=", "=" };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var State = Plugin.State;
			var Result = RecognizerHelper.Find(this, State, Code.String);
			if (Result.Position != -1)
			{
				var Ch = RecognizerHelper.GetLeftRightNode(Code, Result, Plugin);
				if (Ch == null) return ExprRecResult.Failed;

				var Op = Operator.Unknown;
				switch (Result.Index)
				{
					case 0: Op = Operator.Add; break;
					case 1: Op = Operator.Subract; break;
					case 2: Op = Operator.Multiply; break;
					case 3: Op = Operator.Divide; break;
					case 4: Op = Operator.Modolus; break;
					case 5: Op = Operator.ShiftLeft; break;
					case 6: Op = Operator.ShiftRight; break;
					case 7: Op = Operator.BitwiseOr; break;
					case 8: Op = Operator.BitwiseAnd; break;
					case 9: Op = Operator.BitwiseXor; break;

					case 10:
						Ret = new OpExpressionNode(Operator.Assignment, Ch, Code);
						break;

					default:
						throw new ApplicationException();
				}

				if (Op != Operator.Unknown)
				{
					var LinkedNode = new LinkedExprNode(Ch[0]);
					Ch[0] = Plugin.NewNode(new LinkingNode(LinkedNode, Code));
					if (Ch[0] == null) return ExprRecResult.Failed;

					Ret = Plugin.NewNode(new OpExpressionNode(Op, Ch, Code));
					var Dst = Plugin.NewNode(new LinkingNode(LinkedNode, Code));
					if (Ret == null || Dst == null) return ExprRecResult.Failed;

					Ch = new ExpressionNode[] { Dst, Ret };
					Ret = new OpExpressionNode(Operator.Assignment, Ch, Code);
					Ret.LinkedNodes.Add(LinkedNode);
				}

				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class TupleCreatingRecognizer : LanguageNode, IExprRecognizer
	{
		public TupleCreatingRecognizer(LanguageNode Parent)
			: base(Parent)
		{
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var SkippingHandler = Plugin.State.Language.GlobalHandlers;
			if (Code.Find(',', Handlers: SkippingHandler) != -1)
			{
				var Splitted = RecognizerHelper.SplitToParameters(Plugin.State, Code, ',');
				if (Splitted == null) return ExprRecResult.Failed;

				var Members = Expressions.Recognize(Splitted, Plugin);
				if (Members == null) return ExprRecResult.Failed;
				
				Ret = new OpExpressionNode(Operator.Tuple, Members, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class ArrayCreatingRecognizer : LanguageNode, IExprRecognizer
	{
		public ArrayCreatingRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "[" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.Length > 1 && Code[0] == '[' && Code[Code.Length - 1] == ']')
			{
				var SubStr = Code.TrimmedSubstring(Plugin.State, 1, Code.Length - 2);
				if (!SubStr.IsValid) return ExprRecResult.Failed;

				var Groups = Expressions.GetGroups(Plugin, SubStr);
				if (Groups == null) return ExprRecResult.Failed;

				var Nodes = Groups.GetNodes().ToArray();
				Ret = new OpExpressionNode(Operator.Array, Nodes, Code);
				Ret.Data.Set(Groups);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class LogicalRecognizer : LanguageNode, IExprRecognizer
	{
		public LogicalRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			this.Operators = new string[] { "and", "xor", "or" };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			for (var i = 0; i < Operators.Length; i++)
			{
				var Pos = Code.Find(Operators[i], Skip, true, new IdCharCheck(true), SkippingHandlers);
				var Result = new FindResult(i, Pos, Operators[i]);

				if (Result.Position != -1)
				{
					var Ch = RecognizerHelper.GetLeftRightNode(Code, Result, Plugin);
					if (Ch == null) return ExprRecResult.Failed;

					Operator Op;
					if (Result.Index == 0) Op = Operator.And;
					else if (Result.Index == 1) Op = Operator.Inequality;
					else if (Result.Index == 2) Op = Operator.Or;
					else throw new ApplicationException();

					Ret = new OpExpressionNode(Op, Ch, Code);
					return ExprRecResult.Succeeded;
				}
			}

			return ExprRecResult.Unknown;
		}
	}

	public class RefEqualityRecognizer : LanguageNode, IExprRecognizer
	{
		public RefEqualityRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "===", "!==" };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var Result = RecognizerHelper.Find(this, Plugin.State, Code.String);
			if (Result.Position != -1)
			{
				var Ch = RecognizerHelper.GetLeftRightNode(Code, Result, Plugin);
				if (Ch == null) return ExprRecResult.Failed;

				Operator Op;
				if (Result.Index == 0) Op = Operator.RefEquality;
				else if (Result.Index == 1) Op = Operator.RefInequality;
				else throw new ApplicationException();

				Ret = new OpExpressionNode(Op, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

    [Flags]
    public enum RelEquRecognizerFlags : byte
    {
        None = 0,
        DisableOpposed = 1,
    }

	public class RelEquRecognizer : LanguageNode, IExprRecognizer
	{
        public RelEquRecognizerFlags RecFlags;

		public RelEquRecognizer(LanguageNode Parent, RelEquRecognizerFlags Flags)
			: base(Parent)
		{
			Operators = new string[] { "==", "!=", "<=", "<", ">=", ">" };
			NewLineLeft = NewLineRight = Operators;
            this.RecFlags = Flags;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Out)
		{
			var Results = Code.EnumFind(Operators, Skip: Skip, Handlers: SkippingHandlers).ToList();

            if ((RecFlags & RelEquRecognizerFlags.DisableOpposed) != 0)
			{
				for (var i = 0; i < Results.Count; i++)
				{
					if (Results[i].String[0] == '<')
					{
						var Right = Code.Substring(Results[i].Position);
						if (Right.GetBracketPos(false, SkippingHandlers) != -1)
						{
							Results.RemoveAt(i);
							i--;
						}
					}
					else if (Results[i].String[0] == '>')
					{
						var Left = Code.Substring(0, Results[i].Position + 1);
						if (Left.GetBracketPos(true, SkippingHandlers) != -1)
						{
							Results.RemoveAt(i);
							i--;
						}
					}
				}
			}

			if (Results.Count == 0) 
				return ExprRecResult.Unknown;

			var ChNodes = new List<ExpressionNode>(Results.Count + 1);
			for (var i = 0; i <= Results.Count; i++)
			{
				int Start, Length;
				if (i < Results.Count)
				{
					if (i == 0)
					{
						Start = 0;
						Length = Results[i].Position;
					}
					else
					{
						var PrevRes = Results[i - 1];
						Start = PrevRes.Position + PrevRes.String.Length;
						Length = Results[i].Position - Start;
					}
				}
				else
				{
					var PrevRes = Results[i - 1];
					Start = PrevRes.Position + PrevRes.String.Length;
					Length = Code.Length - Start;
				}

				var PStr = Code.TrimmedSubstring(Plugin.State, Start, Length);
				if (!PStr.IsValid) return ExprRecResult.Failed;

				var Node = Expressions.Recognize(PStr, Plugin, true);
				if (Node == null) return ExprRecResult.Failed;
				ChNodes.Add(Node);
			}

			var ResOperators = new List<Operator>(Results.Count);
			for (var i = 0; i < Results.Count; i++)
			{
				var Result = Results[i];
				Operator Op;

				switch (Result.Index)
				{
					case 0: Op = Operator.Equality; break;
					case 1: Op = Operator.Inequality; break;
					case 2: Op = Operator.LessEqual; break;
					case 3: Op = Operator.Less; break;
					case 4: Op = Operator.GreaterEqual; break;
					case 5: Op = Operator.Greater; break;
					default: throw new ApplicationException();
				}

				ResOperators.Add(Op);
			}

			Out = Expressions.ChainedRelation(Plugin, ChNodes, ResOperators, Code);
			return Out == null ? ExprRecResult.Failed : ExprRecResult.Ready;
		}
	}

	public class AdditiveRecognizer : LanguageNode, IExprRecognizer
	{
		public AdditiveRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "+", "-" };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var Result = RecognizerHelper.Find2(this, Plugin.Container, Code.String);
			if (Result.Position != -1)
			{
				var Ch = RecognizerHelper.GetLeftRightNode(Code, Result, Plugin);
				if (Ch == null) return ExprRecResult.Failed;

				Operator Op;
				if (Result.Index == 0) Op = Operator.Add;
				else if (Result.Index == 1) Op = Operator.Subract;
				else throw new ApplicationException();

				Ret = new OpExpressionNode(Op, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class MultiplicativeRecognizer : LanguageNode, IExprRecognizer
	{
		public MultiplicativeRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "*", "/", "%" };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var Result = RecognizerHelper.Find2(this, Plugin.Container, Code.String);
			if (Result.Position != -1)
			{
				var Ch = RecognizerHelper.GetLeftRightNode(Code, Result, Plugin);
				if (Ch == null) return ExprRecResult.Failed;

				Operator Op;
				if (Result.Index == 0) Op = Operator.Multiply;
				else if (Result.Index == 1) Op = Operator.Divide;
				else if (Result.Index == 2) Op = Operator.Modolus;
				else throw new ApplicationException();

				Ret = new OpExpressionNode(Op, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class ShiftRecognizer : LanguageNode, IExprRecognizer
	{
		public ShiftRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "<<", ">>" };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var Result = RecognizerHelper.Find2(this, Plugin.Container, Code.String);
			if (Result.Position != -1)
			{
				var Ch = RecognizerHelper.GetLeftRightNode(Code, Result, Plugin);
				if (Ch == null) return ExprRecResult.Failed;

				Operator Op;
				if (Result.Index == 0) Op = Operator.ShiftLeft;
				else if (Result.Index == 1) Op = Operator.ShiftRight;
				else throw new ApplicationException();

				Ret = new OpExpressionNode(Op, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class BitwiseRecognizer : LanguageNode, IExprRecognizer
	{
		public BitwiseRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "&", "|", "^" };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var Result = RecognizerHelper.Find2(this, Plugin.Container, Code.String);
			if (Result.Position != -1)
			{
				var Ch = RecognizerHelper.GetLeftRightNode(Code, Result, Plugin);
				if (Ch == null) return ExprRecResult.Failed;

				Operator Op;
				if (Result.Index == 0) Op = Operator.BitwiseAnd;
				else if (Result.Index == 1) Op = Operator.BitwiseOr;
				else if (Result.Index == 2) Op = Operator.BitwiseXor;
				else throw new ApplicationException();

				Ret = new OpExpressionNode(Op, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class NegateRecognizer : LanguageNode, IExprRecognizer
	{
		public NegateRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			NewLineRight = Operators = new string[] { "-", "+" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.Length > 0 && Code[0] == '-')
			{
				Ret = RecognizerHelper.OneParamOpNode(Code, Plugin, Operator.Negation);
				return Ret == null ? ExprRecResult.Failed : ExprRecResult.Succeeded;
			}
			else if (Code.Length > 0 && Code[0] == '+')
			{
				Ret = RecognizerHelper.OneParamOpNode(Code, Plugin, Operator.UnaryPlus);
				return Ret == null ? ExprRecResult.Failed : ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class NotRecognizer : LanguageNode, IExprRecognizer
	{
		public NotRecognizer(LanguageNode Parent)
			: base(Parent)
		{
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.StartsWith("not", new IdCharCheck(true)))
			{
				var SubStr = Code.TrimmedSubstring(Plugin.State, 3);
				if (SubStr.Length == 0) return ExprRecResult.Failed;

				Ret = Expressions.Recognize(SubStr, Plugin, true);
				if (Ret == null) return ExprRecResult.Failed;

				var RetCh = new ExpressionNode[] { Ret };
				Ret = new OpExpressionNode(Operator.Not, RetCh, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class CNotRecognizer : LanguageNode, IExprRecognizer
	{
		public CNotRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			NewLineRight = Operators = new string[] { "!" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.StartsWith(Operators, Skip).Position != -1)
			{
				var SubStr = Code.TrimmedSubstring(Plugin.State, 1);
				if (SubStr.Length == 0) return ExprRecResult.Failed;

				Ret = Expressions.Recognize(SubStr, Plugin, true);
				if (Ret == null) return ExprRecResult.Failed;

				var RetCh = new ExpressionNode[] { Ret };
				Ret = new OpExpressionNode(Operator.Not, RetCh, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class AddressRecognizer : LanguageNode, IExprRecognizer
	{
		public AddressRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			NewLineRight = Operators = new string[] { "&" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.Length > 0 && Code[0] == '&')
			{
				Ret = RecognizerHelper.OneParamOpNode(Code, Plugin, Operator.Address);
				if (Ret == null) return ExprRecResult.Failed;
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class ComplementRecognizer : LanguageNode, IExprRecognizer
	{
		public ComplementRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			NewLineRight = Operators = new string[] { "~" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.Length > 0 && Code[0] == '~')
			{
				Ret = RecognizerHelper.OneParamOpNode(Code, Plugin, Operator.Complement);
				return Ret == null ? ExprRecResult.Failed : ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class IncDecRecognizer : LanguageNode, IExprRecognizer
	{
		public IncDecRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			NewLineLeft = Operators = new string[] { "++", "--" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			Operator Op;
			if (Code.EndsWith("++")) Op = Operator.Increase;
			else if (Code.EndsWith("--")) Op = Operator.Decrease;
			else return ExprRecResult.Unknown;
			
			var ChildStr = Code.TrimmedSubstring(Plugin.State, 0, Code.Length - 2);
			if (!ChildStr.IsValid) return ExprRecResult.Failed;

			var Child = Expressions.Recognize(ChildStr, Plugin, true);
			if (Child == null) return ExprRecResult.Failed;

			var Children = new ExpressionNode[] { Child };
			Ret = new OpExpressionNode(Op, Children, Code);
			return ExprRecResult.Succeeded;
		}
	}

	public class IndirectionRecognizer : LanguageNode, IExprRecognizer
	{
		public IndirectionRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			NewLineRight = Operators = new string[] { "*" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.Length > 0 && Code[0] == '*')
			{
				var PtrCode = Code.TrimmedSubstring(Plugin.State, 1);
				if (!PtrCode.IsValid) return ExprRecResult.Failed;

				var PtrNode = Expressions.Recognize(PtrCode, Plugin, true);
				if (PtrNode == null) return ExprRecResult.Failed;

				Ret = Expressions.Indirection(Plugin, PtrNode, Code);
				return Ret == null ? ExprRecResult.Failed : ExprRecResult.Ready;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class CallRecognizer : LanguageNode, IExprRecognizer, ICallParamRecognizer
	{
		public List<IBuiltinFuncRecognizer> Recognizers;

		public CallRecognizer(LanguageNode Parent, List<IBuiltinFuncRecognizer> Recognizers)
			: base(Parent)
		{
			this.Recognizers = Recognizers;
			Operators = NewLineRight = new string[] { "(" };
			NewLineLeft = new string[] {  "(", ")" };
		}

		public ExpressionNode[] ProcessParameters(PluginRoot Plugin, CodeString Function, CodeString Parameters)
		{
			var ParamList = RecognizerHelper.GetParamList(Plugin.State, Parameters);
			if (ParamList == null) return null;

			return ProcessParameters(Plugin, Function, ParamList);
		}

		public ExpressionNode[] ProcessParameters(PluginRoot Plugin, CodeString Function, CodeString[] Parameters)
		{
			var RetValue = true;
			var Nodes = new ExpressionNode[Parameters.Length + 1];

			if (Function.IsValid)
			{
				Nodes[0] = Expressions.Recognize(Function, Plugin);
				if (Nodes[0] == null) RetValue = false;
			}

			for (var i = 0; i < Parameters.Length; i++)
			{
				var NamePos = Parameters[i].Find(':', false, SkippingHandlers);
				if (NamePos != -1)
				{
					var Name = Parameters[i].Substring(0, NamePos).Trim();
					var Value = Parameters[i].Substring(NamePos + 1).Trim();

					if (Name.IsValidIdentifierName)
					{
						var Node = Expressions.Recognize(Value, Plugin);
						if (Node == null) { RetValue = false; continue; }

						Nodes[i + 1] = Plugin.NewNode(new NamedParameterNode(Parameters[i], Node, Name));
						if (Nodes[i + 1] == null) { RetValue = false; continue; }
					}
				}

				Nodes[i + 1] = Expressions.Recognize(Parameters[i], Plugin);
				if (Nodes[i + 1] == null) { RetValue = false; continue; }
			}

			return RetValue ? Nodes : null;
		}

		public bool GetParameters(CompilerState State, CodeString Code, out CodeString Function, out CodeString Parameters)
		{
			if (Code.Length > 0 && Code[Code.Length - 1] == ')')
			{
				Function = Code;
				Parameters = RecognizerHelper.ExtractBracket(State, Code, ')', ref Function, true);
				return Parameters.IsValid && Parameters.VerifyNotEmpty(State, Code);
			}
			else
			{
				Function = new CodeString();
				Parameters = new CodeString();

				State.Messages.Add(MessageId.NotExpected, Code);
				return false;
			}
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.Length > 0 && Code[Code.Length - 1] == ')')
			{
				var State = Plugin.State;

				var Called = Code;
				var ParamStr = RecognizerHelper.ExtractBracket(State, Code, ')', ref Called, true);
				if (!ParamStr.IsValid || !Called.VerifyNotEmpty(State, Code)) 
					return ExprRecResult.Failed;

				var ParamList = RecognizerHelper.GetParamList(State, ParamStr);
				if (ParamList == null) return ExprRecResult.Failed;

				CodeString[] GenericParams;
				var GenericRec = State.Language.GenericRecognizer;
				var GRes = GenericRec.GetGenericParams(State, ref Called, out GenericParams);
				if (GRes == SimpleRecResult.Failed) return ExprRecResult.Failed;

				if (Recognizers != null)
				{
					var ParamArray = ParamList.ToArray();
					for (var i = 0; i < Recognizers.Count; i++)
					{
						var Res = Recognizers[i].Recognize(Code, Called, 
							ParamArray, GenericParams, Plugin, ref Ret);

						if (Res != ExprRecResult.Unknown) return Res;
					}
				}

				var Nodes = ProcessParameters(Plugin, Called, ParamList);
				if (Nodes == null) return ExprRecResult.Failed;

				Ret = new OpExpressionNode(Operator.Call, Nodes, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class IndexRecognizer : LanguageNode, IExprRecognizer
	{
		public IndexRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = NewLineRight = new string[] { "[" };
			NewLineLeft = new string[] { "[" , "]" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.Length > 0 && Code[Code.Length - 1] == ']')
			{
				var State = Plugin.State;

				var ArrayStr = Code;
				var ParamStr = RecognizerHelper.ExtractBracket(State, Code, ']', ref ArrayStr, true);
				if (!ParamStr.IsValid || !ArrayStr.VerifyNotEmpty(State, Code))
					return ExprRecResult.Failed;

				var ParamList = RecognizerHelper.GetParamList(State, ParamStr);
				if (ParamList == null) return ExprRecResult.Failed;

				var ParamNodes = Expressions.Recognize(ParamList, Plugin);
				var ArrayNode = Expressions.Recognize(ArrayStr, Plugin);
				if (ParamNodes == null || ArrayNode == null) return ExprRecResult.Failed;

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

				Ret = new OpExpressionNode(Operator.Index, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class NullCoalescingRecognizer : LanguageNode, IExprRecognizer
	{
		public NullCoalescingRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "??" };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var Container = Plugin.Container;
			var Result = RecognizerHelper.Find2(this, Plugin.Container, Code.String);
			if (Result.Position != -1)
			{
				var State = Plugin.State;
				var GlobalContainer = Container.GlobalContainer;

				var LeftRight = RecognizerHelper.GetLeftRightNode(Code, Result, Plugin);
				if (LeftRight == null) return ExprRecResult.Failed;
				var Linked = new LinkedExprNode(LeftRight[0]);

				var Null = Plugin.NewNode(Constants.GetNullValue(Plugin.Container, Code));
				var RelLnk = Plugin.NewNode(new LinkingNode(Linked, Code));
				if (RelLnk == null || Null == null) return ExprRecResult.Failed;

				var RelCh = new ExpressionNode[] {RelLnk, Null };
				var Rel = Plugin.NewNode(new OpExpressionNode(Operator.Inequality, RelCh, Code));
				if (Rel == null) return ExprRecResult.Failed;

				var RetLnk = Plugin.NewNode(new LinkingNode(Linked, Code));
				if (RetLnk == null) return ExprRecResult.Failed;
				var RetCh = new ExpressionNode[] {Rel, RetLnk, LeftRight[1] };
				Ret = new OpExpressionNode(Operator.Condition, RetCh, Code);
				Ret.LinkedNodes = new List<LinkedExprNode>() { Linked };
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class SafeNavigationRecognizer : LanguageNode, IExprRecognizer
	{
		public SafeNavigationRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { "?.", "?->" };
			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var Container = Plugin.Container;
			var Result = RecognizerHelper.Find2(this, Plugin.Container, Code.String);
			if (Result.Position != -1)
			{
				var State = Plugin.State;
				var GlobalContainer = Container.GlobalContainer;

				var Left_Str = Code.TrimmedSubstring(State, 0, Result.Position);
				var Right_Str = Code.TrimmedSubstring(State, Result.NextChar);
				if (!Left_Str.IsValid || !Right_Str.IsValid) return ExprRecResult.Failed;

				var Left = Expressions.Recognize(Left_Str, Plugin, true);
				if (Left == null) return ExprRecResult.Failed;
				var Linked = new LinkedExprNode(Left);

				//--------------------------------------------------------------------------------------
				var Null = Plugin.NewNode(Constants.GetNullValue(Container, Code));
				if (Null == null) return ExprRecResult.Failed;
				var RelLnk = Plugin.NewNode(new LinkingNode(Linked, Code));
				if (RelLnk == null) return ExprRecResult.Failed;

				var RelCh = new ExpressionNode[] {RelLnk, Null };
				var Rel = Plugin.NewNode(new OpExpressionNode(Operator.Inequality, RelCh, Code));
				if (Rel == null) return ExprRecResult.Failed;

				//--------------------------------------------------------------------------------------
				var ThenSrc = Plugin.NewNode(new LinkingNode(Linked, Code));
				if (ThenSrc == null) return ExprRecResult.Failed;

				if (Result.Index == 1)
				{
					ThenSrc = Expressions.Indirection(Plugin, ThenSrc, Code);
					if (ThenSrc == null) return ExprRecResult.Failed;
				}

				var MemberNode = Plugin.NewNode(new StrExpressionNode(Right_Str));
				if (MemberNode == null) return ExprRecResult.Failed;
				var ThenCh = new ExpressionNode[] {ThenSrc, MemberNode };
				var Then = Plugin.NewNode(new OpExpressionNode(Operator.Member, ThenCh, Code));
				if (Then == null) return ExprRecResult.Failed;

				//--------------------------------------------------------------------------------------
				var Else = Plugin.NewNode(Constants.GetNullValue(Container, Code));
				if (Else == null) return ExprRecResult.Failed;
				var RetCh = new ExpressionNode[] {Rel, Then, Else };
				Ret = new OpExpressionNode(Operator.Condition, RetCh, Code);
				Ret.LinkedNodes = new List<LinkedExprNode>() { Linked };
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

    [Flags]
    public enum MemberRecognizerFlags : byte
    {
        None = 0,
        AllowScopeResolution = 1,
    }

	public class MemberRecognizer : LanguageNode, IExprRecognizer
	{
		public MemberRecognizer(LanguageNode Parent, MemberRecognizerFlags Flags = MemberRecognizerFlags.None)
			: base(Parent)
		{
			if ((Flags & MemberRecognizerFlags.AllowScopeResolution) != 0)
                Operators = new string[] { ".", "->", "::" };
            else Operators = new string[] { ".", "->" };

			NewLineLeft = NewLineRight = Operators;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var Container = Plugin.Container;
			var Result = RecognizerHelper.Find2(this, Plugin.Container, Code.String);
			if (Result.Position == -1) return ExprRecResult.Unknown;

			var RightStr = Code.Substring(Result.NextChar).Trim();
			if (RightStr.IsValidIdentifierName || RightStr.IsNumber)
			{
				var State = Plugin.State;
				var LeftStr = Code.TrimmedSubstring(State, 0, Result.Position);
				if (!LeftStr.IsValid) return ExprRecResult.Failed;

                var Op = Operator.Member;
				var Left = Expressions.Recognize(LeftStr, Plugin, true);
				if (Left == null) return ExprRecResult.Failed;

                if (Result.Index == 2)
                {
                    Op = Operator.ScopeResolution;
                }
                else
                {
                    Op = Operator.Member;
                    if (Result.Index == 1)
                    {
                        Left = Expressions.Indirection(Plugin, Left, Code);
                        if (Left == null) return ExprRecResult.Failed;
                    }
                }

				var Right = Plugin.NewNode(new StrExpressionNode(RightStr));
				if (Right == null) return ExprRecResult.Failed;
				
				var Ch = new ExpressionNode[] { Left, Right };
                Ret = new OpExpressionNode(Op, Ch, Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class ExprVarDeclRecognizer : LanguageNode, IExprRecognizer
	{
		public ExprVarDeclRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			Operators = new string[] { " ", "\t", "\r", "\n" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			var Result = RecognizerHelper.Find(this, Plugin.State, Code.String);
			if (Result.Position != -1)
			{
				var VarName = Code.Substring(Result.Position).Trim();
				if (!VarName.IsValidIdentifierName) return ExprRecResult.Unknown;

				var Container = Plugin.Container;
				var State = Plugin.State;

				var TypeName = Code.Substring(0, Result.Position).Trim();
				Ret = Plugin.DeclareVarAndCreateIdNode(Code, TypeName, VarName);
				if (Ret == null) return ExprRecResult.Failed;
				else return ExprRecResult.Ready;
			}

			return ExprRecResult.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