Click here to Skip to main content
15,879,348 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;

namespace Bird.Recognizers
{
	public class TestScopeRecognizer : LanguageNode, IExprRecognizer
	{
		public TestScopeRecognizer(LanguageNode Parent)
			: base(Parent)
		{
			NewLineRight = Operators = new string[] { "testscope" };
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Out)
		{
			var Result = Code.StartsWith(Operators, Skip, new IdCharCheck(true));
			if (Result.Position != -1)
			{
				var State = Plugin.State;
				var Right = Code.Substring(Result.String.Length).Trim();
				Right = Right.TrimOneBracket(SkippingHandlers);

				if (Right.Length == 0)
				{
					State.Messages.Add(MessageId.DeficientExpr, Code);
					return ExprRecResult.Failed;
				}

				var Scope = new CodeScopeNode(Plugin.Container, Right);
				if (!Scope.ProcessCode()) return ExprRecResult.Failed;

				var List = Scope.GetContainerId("retvar", x => x is LocalVariable);
				var RetVar = Identifiers.SelectIdentifier(State, List, Code) as LocalVariable;
				if (RetVar == null) return ExprRecResult.Failed;

				Out = new ScopeExpressionNode(Scope, Code)
				{
					ReturnVar = RetVar,
				};

				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

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

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Out)
		{
			var Result = Code.StartsWith(Operators, Skip, new IdCharCheck(true));
			if (Result.Position != -1)
			{
				var State = Plugin.State;
				var Right = Code.Substring(Result.String.Length).Trim();
				Right = Right.TrimOneBracket(SkippingHandlers);

				if (Right.Length == 0)
				{
					State.Messages.Add(MessageId.DeficientExpr, Code);
					return ExprRecResult.Failed;
				}

				var TypeMngrPlugin = Plugin.GetPlugin<TypeMngrPlugin>();
				if (TypeMngrPlugin == null) return ExprRecResult.Unknown;

				var OldCheckingMode = TypeMngrPlugin.CheckingMode;
				if (Result.Index == 0) TypeMngrPlugin.CheckingMode = CheckingMode.Checked;
				else if (Result.Index == 1) TypeMngrPlugin.CheckingMode = CheckingMode.Unchecked;
				else throw new ApplicationException();

				Out = Expressions.Recognize(Right, Plugin);
				TypeMngrPlugin.CheckingMode = OldCheckingMode;

				if (Out == null) return ExprRecResult.Failed;
				else return ExprRecResult.Ready;
			}

			return ExprRecResult.Unknown;
		}
	}

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

		public CodeString[] SplitToParameters(CompilerState State, CodeString Self, bool EnableMessages = true)
		{
			return RecognizerHelper.SplitToParameters(State, Self, ',', EnableMessages);
		}
	}

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

		public SimpleRecResult GetGenericParams(CompilerState State, ref CodeString Code, 
			 out CodeString[] Out, bool EnableMessages = true)
		{
			Out = null;
			if (Code.Length > 0 && Code[Code.Length - 1] == '>')
			{
				var BracketPos = Code.GetBracketPos(State, true);
				if (BracketPos == -1) return SimpleRecResult.Failed;

				var ParamStart = BracketPos + 1;
				var StrParams = Code.TrimmedSubstring(State, ParamStart, Code.Length - ParamStart - 1);
				if (!StrParams.IsValid) return SimpleRecResult.Failed;

				Out = RecognizerHelper.GetParamList(State, StrParams);
				if (Out == null) return SimpleRecResult.Failed;

				Code = Code.Substring(0, BracketPos).Trim();
			}

			return SimpleRecResult.Unknown;
		}

        public override void Init(LanguageInitData InitData)
		{
			base.Init(InitData);

            foreach (var e in Language.Root.GetObjects<RelEquRecognizer>())
				e.RecFlags |= RelEquRecognizerFlags.DisableOpposed;

			var ListDisableFind = new List<string>();
			var ListDisableSkip = new List<string>();
            foreach (var e in Language.Root.GetObjects<LogicalRecognizer>())
			{
				if (e.Operators != null) ListDisableFind.AddRange(e.Operators);
				if (e.Skip != null) ListDisableFind.AddRange(e.Skip);
			}

			var DisableFind = Helper.ToArrayWithoutSame(ListDisableFind);
			var DisableSkip = Helper.GetSkipList(DisableFind, ListDisableSkip);

            foreach (var e in Language.Root.GetObjects<BracketRecognizer>())
			{
				e.GenericBracketSkipOptions = new GenericBracketSkipOptions()
				{
					Enabled = true,
					DisableFind = DisableFind,
					DisableSkip = DisableSkip,
					SkippingHandlers = SkippingHandlers,
				};
			}
		}
	}

	public class BracketGroupRecognizer : LanguageNode, IGroupRecognizer
	{
		public char BracketLeft = '{';
		public char BracketRight = '}';

		public BracketGroupRecognizer(LanguageNode Parent, char BracketLeft = '{', char BracketRight = '}')
			: base(Parent)
		{
		}

		public static NodeGroup GetGroups(PluginRoot Plugin, CodeString Code, char BracketLeft = '{', char BracketRight = '}')
		{
			var Ret = new NodeGroup(Code);
			var State = Plugin.State;

			var List = RecognizerHelper.SplitToParameters(State, Code, ',');
			if (List == null) return null;

			for (var i = 0; i < List.Length; i++)
			{
				var Param = List[i];
				if (Param.Length > 1 && Param[0] == BracketLeft && Param[Param.Length] == BracketLeft)
				{
					Param = Param.Substring(1, Param.Length - 1).Trim();
					Ret.Children.Add(Expressions.GetGroups(Plugin, Param));
				}
				else
				{
					var Node = Expressions.Recognize(Param, Plugin);
					if (Node == null) return null;

					Ret.Children.Add(Node);
				}
			}

			return Ret;
		}

		public NodeGroup GetGroups(PluginRoot Plugin, CodeString Code)
		{
			return GetGroups(Plugin, Code, BracketLeft, BracketRight);
		}
	}

	public struct GenericBracketSkipOptions
	{
		public bool Enabled;
		public string[] DisableFind;
		public string[] DisableSkip;
		public IList<IResultSkippingHandler> SkippingHandlers;
	}

	public enum GenericBracketSkipMode : byte
	{
		Disabled,
		Enabled,
		IfNoLogicalOp,
	}

	public class BracketRecognizer : LanguageNode, IExprRecognizer, IIdRecognizer, IResultSkippingHandler
	{
		public GenericBracketSkipOptions GenericBracketSkipOptions;

		public BracketRecognizer(LanguageNode Parent, GenericBracketSkipOptions GenericBracketSkipMode = new GenericBracketSkipOptions())
			: base(Parent)
		{
			this.GenericBracketSkipOptions = GenericBracketSkipMode;
		}

		static bool Check(CompilerState State, CodeString Code)
		{
			if (Code[0] == '(' && Code.GetBracketPos(State)  == -1)
				return false;

            if (Code[0] == ')')
            {
                State.Messages.Add(MessageId.ZNumErr, Code.Substring(0, 1));
                return false;
            }

			var P = Code.Length - 1;
            if (Code[P] == '(')
            {
                State.Messages.Add(MessageId.ZNumErr, Code.Substring(P));
                return false;
            }

			if (Code[P] == ')' && Code.GetBracketPos(State, true) == -1)
				return false;

			return true;
		}

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (!Check(Plugin.State, Code)) return ExprRecResult.Failed;

			var NewCode = Code.TrimBrackets(Plugin.State);
			if (!NewCode.IsValid) return ExprRecResult.Failed;
			if (NewCode.Length == Code.Length) return ExprRecResult.Unknown;

			Ret = Expressions.Recognize(NewCode, Plugin, true);
			return Ret == null ? ExprRecResult.Failed : ExprRecResult.Ready;
		}

		public SimpleRecResult Recognize(IdContainer Container, CodeString Code, GetIdOptions Options, ref Identifier Ret)
		{
			if (!Check(Container.State, Code)) return SimpleRecResult.Failed;

			var NewCode = Code.TrimBrackets(Container.State);
			if (!NewCode.IsValid) return SimpleRecResult.Failed;
			if (NewCode.Length == Code.Length) return SimpleRecResult.Unknown;

			Ret = Identifiers.Recognize(Container, NewCode, Options);
			return Ret == null ? SimpleRecResult.Failed : SimpleRecResult.Succeeded;
		}

		SkippingHandlerResult SkipBracket(ref ResultSkippingManager RSM)
		{
			if (RSM.Back)
			{
				var NewString = RSM.String.Substring(0, RSM.Current + 1);
				var Pos = NewString.GetBracketPos(true, RSM.SkippingHandlers);
				if (Pos != -1) return new SkippingHandlerResult(Pos);
			}
			else
			{
				var NewString = RSM.String.Substring(RSM.Current);
				var Pos = NewString.GetBracketPos(false, RSM.SkippingHandlers);
				if (Pos != -1) return new SkippingHandlerResult(Pos + RSM.Current);
			}

			return new SkippingHandlerResult(-1);
		}

		public SkippingHandlerResult SkipResult(ref ResultSkippingManager RSM)
		{
			if (!RSM.DoNotSkipBrackets)
			{
				var Char = RSM.CurrentChar;
				if (GenericBracketSkipOptions.Enabled)
				{
					if ((Char == '<' && !RSM.Back) || (Char == '>' && RSM.Back))
					{
						var Result = SkipBracket(ref RSM);
						if (Result.Index == -1 || GenericBracketSkipOptions.DisableFind == null)
							return Result;

						var Substring = RSM.String.SubstringFromTo(RSM.Current + 1, Result.Index - 1);
						var FindRes = Substring.Find(GenericBracketSkipOptions.DisableFind, 
							GenericBracketSkipOptions.DisableSkip, false, new IdCharCheck(true),
							GenericBracketSkipOptions.SkippingHandlers);

						if (FindRes.Position == -1)
							return Result;
					}
				}

				if (Helper.GetBracket(Char, RSM.Back))
					return SkipBracket(ref RSM);
			}

			return new SkippingHandlerResult(-1);
		}
	}

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

		public ExprRecResult Recognize(CodeString Code, PluginRoot Plugin, ref ExpressionNode Ret)
		{
			if (Code.IsValidIdentifierName)
			{
				Ret = new StrExpressionNode(Code);
				return ExprRecResult.Succeeded;
			}

			return ExprRecResult.Unknown;
		}
	}

	public class RetValLessRecognizer : LanguageNode, IRetValLessRecognizer, ICallParamRecognizer
	{
		public IExprRecognizer[] RunBefore;
		CallRecognizer CallRecognizer;

		public RetValLessRecognizer(LanguageNode Parent, IExprRecognizer[] RunBefore = null)
			: base(Parent)
		{
			this.RunBefore = RunBefore;
		}

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

		public static int FindParamPosition(CompilerState State, StringSlice Code)
		{
			var Ok = false;
			var Handlers = State.Language.GlobalHandlers;
			var RSM = new ResultSkippingManager(Handlers, Code);

			var Language = State.Language;
			var LangRoot = Language.Root;
			var CastRecognizer = Language.Root.GetObject<CastRecognizer>(false);

			while (RSM.Loop())
			{
				var Pos = RSM.Current;
				var Chr = Code[Pos];
				if (!Helper.IsIdChar(Chr))
				{
					if (!Ok) continue;

					if (Chr == '(')
					{
						var Brackets = Code.Substring(Pos);
						if (CastRecognizer != null && CastRecognizer.IsCastString(State, Brackets))
							return Pos;

						if (Brackets.GetBracketPos(false, Handlers) == Brackets.Length - 1)
							return Pos;
					}
					else if (char.IsWhiteSpace(Chr))
					{
						// ambiguous: Print (Obj is object).ToString()
						var After = Code.Substring(Pos + 1).Trim();
						var AfterChr = After.Length > 0 ? After[0] : '\0';
						if (Helper.IsIdChar(AfterChr) || AfterChr == '(' || AfterChr == '[')
							return Pos;
					}

                    if (Code.SubstringEquals(Pos, LangRoot.OnlyRight, LangRoot.OnlyRightSkip,
                        false, new IdCharCheck(true)).Position != -1)
                    {
                        return Pos;
                    }

                    for (var i = 0; i < Language.ExprRecognizers.Length; i++)
					{
						var Rec = Language.ExprRecognizers[i] as SkippedBetweenRecognizer;
						if (Rec != null && Code.SubstringEquals(Pos, Rec.Operators, Rec.Skip).Index != -1)
							return Pos;
					}
				}
				else
				{
					Ok = true;
				}
			}

			return -1;
		}

		public bool GetParameters(CompilerState State, CodeString Code, out CodeString Function, out CodeString Parameters)
		{
			var Pos = FindParamPosition(State, Code.String);
			if (Pos != -1)
			{
				Function = Code.Substring(0, Pos).Trim();
				var Handlers = State.Language.GlobalHandlers;
				Parameters = Code.Substring(Pos).TrimOneBracket(Handlers);
			}
			else
			{
				Function = Code;
				Parameters = Code.Substring(Code.Length);
			}

			return true;
		}

		public ExpressionNode[] ProcessParameters(PluginRoot Plugin, CodeString Function, CodeString[] Parameters)
		{
			return CallRecognizer.ProcessParameters(Plugin, Function, Parameters);
		}

		public ExpressionNode[] ProcessParameters(PluginRoot Plugin, CodeString Function, CodeString Parameters)
		{
			return CallRecognizer.ProcessParameters(Plugin, Function, Parameters);
		}

		public ExpressionNode CreateFuncCallNode(PluginRoot Plugin, CodeString Code)
		{
			CodeString Function, Parameters;
			if (!GetParameters(Plugin.State, Code, out Function, out Parameters))
				return null;

			var Ch = CallRecognizer.ProcessParameters(Plugin, Function, Parameters);
			if (Ch == null) return null;

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

		public ExpressionNode Recognize(CodeString Code, PluginRoot Plugin)
		{
			ExpressionNode Out;
			var Res = Expressions.Recognize(Code, Plugin, RunBefore, out Out);
			if (Res == SimpleRecResult.Unknown) return CreateFuncCallNode(Plugin, Code);
			else return Res == SimpleRecResult.Succeeded ? Out : null;
		}
	}
}

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