Click here to Skip to main content
15,886,362 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.Collections.Generic;
using System.Numerics;

namespace Bird.NativeCode
{
    public struct NCNeededRunBefore
    {
        public ExpressionNode Node;
        //public Identifier[] Identifiers;

        public NCNeededRunBefore(ExpressionNode Node/*, Identifier[] Identifiers*/)
        {
            this.Node = Node;
            //this.Identifiers = Identifiers;
        }
    }

    public struct NCExpressionRunBefores
    {
        public NCNeededRunBefore[] NeededRunBefores;
        /*
        public Identifier[] GetIdentifiersToShare()
        {
            var List = new List<Identifier>();
            for (var i = 0; i < NeededRunBefores.Length; i++)
            {
                var RunBefore = NeededRunBefores[i];
                for (var j = 0; j < RunBefore.Identifiers.Length; j++)
                {
                    var Id = RunBefore.Identifiers[j];
                    if (!List.Contains(Id)) List.Add(Id);
                }
            }

            return List.ToArray();
        }*/
    }

	public static class NCExpressions
	{
		public static ExpressionNode[] GetArrayDimensions(PluginRoot Plugin,
			ExpressionNode Node, CodeString Code)
		{
			var Ch = Node.Children;
			var Dimensions = new ExpressionNode[Ch.Length - 1];

			for (var i = 0; i < Dimensions.Length; i++)
			{
				Dimensions[i] = GetArrayDimension(Plugin, Ch[0], i, Code);
				if (Dimensions[i] == null) return null;
			}

			return Dimensions;
		}

		public static ExpressionNode[] GetArrayIndices(PluginRoot Plugin,
			ExpressionNode Node, CodeString Code, Identifier IndexType = null)
		{
			var Ch = Node.Children;
			var Indices = new ExpressionNode[Ch.Length - 1];

			for (var i = 0; i < Indices.Length; i++)
			{
				Indices[i] = Ch[i + 1];
				if (IndexType != null && !Indices[i].Type.IsEquivalent(IndexType))
				{
					Indices[i] = Expressions.Convert(Indices[i], IndexType, Plugin);
					if (Indices[i] == null) return null;
				}
			}

			return Indices;
		}

		public static ExpressionNode FlattenIndicesWithoutTempVar(PluginRoot Plugin,
			ExpressionNode Node, CodeString Code, Identifier IndexType = null)
		{
			var Indices = GetArrayIndices(Plugin, Node, Code, IndexType);

			var ArrayType = Node.Children[0].Type.RealId as ArrayType;
			if (ArrayType.Dimensions == 1) return Indices[0];

			var Dimensions = GetArrayDimensions(Plugin, Node, Code);
			return FlattenIndicesWithoutTempVar(Plugin, Indices, Dimensions, Code);
		}

		public static ExpressionNode FlattenIndicesWithoutTempVar(PluginRoot Plugin,
			ExpressionNode[] Indices, ExpressionNode[] Dimensions, CodeString Code)
		{
			if (Dimensions.Length == 1)
				return Indices[0];

			var Ret = (ExpressionNode)null;
			for (var i = Dimensions.Length - 1; i >= 0; i--)
			{
				var Chi = Indices[i];
				for (var j = i + 1; j < Dimensions.Length; j++)
				{
					var MulCh = new ExpressionNode[] { Chi, Dimensions[j] };
					Chi = Plugin.NewNode(new OpExpressionNode(Operator.Multiply, MulCh, Code));
					if (Chi == null) return null;
				}

				if (Ret != null)
				{
					var AddCh = new ExpressionNode[] { Ret, Chi };
					Ret = Plugin.NewNode(new OpExpressionNode(Operator.Add, AddCh, Code));
					if (Ret == null) return null;
				}
				else
				{
					Ret = Chi;
				}
			}

			return Ret;
		}
		
		public static ExpressionNode FlattenIndices(PluginRoot Plugin,
			ExpressionNode Node, CodeString Code, Identifier IndexType = null)
		{
			var Indices = GetArrayIndices(Plugin, Node, Code, IndexType);

			var ArrayType = Node.Children[0].Type.RealId as ArrayType;
			if (ArrayType.Dimensions == 1) return Indices[0];

			var Dimensions = GetArrayDimensions(Plugin, Node, Code);
			return FlattenIndices(Plugin, Indices, Dimensions, Code, IndexType);
		}

		public static ExpressionNode FlattenIndices(PluginRoot Plugin, ExpressionNode[] Indices,
			ExpressionNode[] Dimensions, CodeString Code, Identifier TempVarType = null)
		{
			if (Dimensions.Length == 1)
				return Indices[0];

			var Ret = (ExpressionNode)null;
			var MulVar = (Identifier)null;
			var Container = Plugin.Container;
			var State = Plugin.State;

			if (Dimensions.Length >= 2)
			{
				var NCPlugin = Plugin.GetPlugin<NCPlugin>();
				var DeclContainer = NCPlugin.DeclContainer;
				MulVar = DeclContainer.CreateAndDeclareVariable(State.AutoVarName, TempVarType);
				if (MulVar == null) return null;
			}

			for (var i = Dimensions.Length - 1; i >= 0; i--)
			{
				var Chi = Indices[i];
				var LinkedNode = (LinkedExprNode)null;
				if (MulVar != null && i != 1)
				{
					ExpressionNode[] AssignmentCh;
					if (i == Dimensions.Length - 1)
					{
						var Dst = Plugin.NewNode(new IdExpressionNode(MulVar, Code));
						if (Dst == null) return null;

						AssignmentCh = new ExpressionNode[] { Dst, Dimensions[i] };
					}
					else
					{
						var Dst = Plugin.NewNode(new IdExpressionNode(MulVar, Code));
						var MulSrc = Plugin.NewNode(new IdExpressionNode(MulVar, Code));
						if (Dst == null || MulSrc == null) return null;

						var MulCh = new ExpressionNode[] { MulSrc, Dimensions[i] };
						var MulNode = Plugin.NewNode(new OpExpressionNode(Operator.Multiply, MulCh, Code));
						if (MulNode == null) return null;

						AssignmentCh = new ExpressionNode[] { Dst, MulNode };
					}

					var Assignment = Plugin.NewNode(new OpExpressionNode(Operator.Assignment, AssignmentCh, Code));
					if (Assignment == null) return null;

					LinkedNode = new LinkedExprNode(Assignment, LinkedNodeFlags.NotRemovable);
				}

				if (MulVar != null && i != Dimensions.Length - 1)
				{
					var MulNode = Plugin.NewNode(new IdExpressionNode(MulVar, Code));
					if (MulNode == null) return null;

					var MulCh = new ExpressionNode[] { Chi, MulNode };
					Chi = Plugin.NewNode(new OpExpressionNode(Operator.Multiply, MulCh, Code));
					if (Chi == null) return null;
				}

				if (Ret != null)
				{
					var AddCh = new ExpressionNode[] { Ret, Chi };
					var AddNode = new OpExpressionNode(Operator.Add, AddCh, Code);
					if (LinkedNode != null) AddNode.LinkedNodes.Add(LinkedNode);

					Ret = Plugin.NewNode(AddNode);
					if (Ret == null) return null;
				}
				else
				{
					Ret = Chi;
					if (LinkedNode != null)
						Ret.LinkedNodes.Add(LinkedNode);
				}
			}

			return Ret;
		}

		public static ExpressionNode GetArrayDimension(PluginRoot Plugin, 
			ExpressionNode Array, int Index, CodeString Code)
		{
			var Container = Plugin.Container;
			var Type = Array.Type.RealId;

			if (Type is NonrefArrayType)
			{
				var Arr = Type as NonrefArrayType;
				if (Arr.Lengths == null) throw new ArgumentOutOfRangeException("Index");
				return Plugin.NewNode(Constants.GetUIntPtrValue(Container, Arr.Lengths[Index], Code));
			}
			else if (Type is RefArrayType)
			{
				var Arr = Type as RefArrayType;
				var DimensionsId = Identifiers.GetMember(Plugin.State, Arr, "Dimensions", Code);
				if (DimensionsId == null) return null;

				var DimensionsIdNode = Plugin.NewNode(new IdExpressionNode(DimensionsId, Code));
				if (DimensionsIdNode == null) return null;

				var DimensionsCh = new ExpressionNode[] { Array, DimensionsIdNode };
				var Dimensions = Plugin.NewNode(new OpExpressionNode(Operator.Member, DimensionsCh, Code));
				if (Dimensions == null) return null;

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

				var IndexCh = new ExpressionNode[] { Dimensions, IndexValue };
				return Plugin.NewNode(new OpExpressionNode(Operator.Index, IndexCh, Code));
			}
			else
			{
				throw new NotImplementedException();
			}
		}

		public static bool IsOverflowableOp(Operator Op)
		{
			return Op == Operator.Add || Op == Operator.Subract || Op == Operator.Multiply ||
				Operators.IsIncDec(Op) || Op == Operator.Cast || Op == Operator.Negation;
		}

		public static ExpressionNode ThrowSystemException(PluginRoot Plugin, string ExceptionType,
			CodeString Code, BeginEndMode BEMode = BeginEndMode.Both)
		{
			var System = Identifiers.GetByFullNameFast<Namespace>(Plugin.State, "System");
			if (System == null) return null;

			return Throw(Plugin, System, new CodeString(ExceptionType), Code, BEMode);
		}

		public static ExpressionNode Throw(PluginRoot Plugin, Identifier ContainerId, string ExceptionType,
			CodeString Code, BeginEndMode BEMode = BeginEndMode.Both)
		{
			return Throw(Plugin, ContainerId, new CodeString(ExceptionType), Code, BEMode);
		}

		public static ExpressionNode Throw(PluginRoot Plugin, Identifier ContainerId, CodeString ExceptionType,
			CodeString Code, BeginEndMode BEMode = BeginEndMode.Both)
		{
			var Options = new GetIdOptions() { EnableMessages = true, Func = x => x.RealId is ClassType };
			var IdExceptionType = Identifiers.GetFromMembers(ContainerId, ExceptionType, Options);
			if (IdExceptionType == null) return null;

			return Throw(Plugin, IdExceptionType, Code, BEMode);
		}

		public static ExpressionNode Throw(PluginRoot Plugin, Identifier ExceptionType,
			CodeString Code, BeginEndMode BEMode = BeginEndMode.Both)
		{
			var GlobalContainer = Plugin.Container.GlobalContainer;
			if ((BEMode & BeginEndMode.Begin) != 0 && !Plugin.Begin())
				return null;

			var IdNode = Plugin.NewNode(new IdExpressionNode(ExceptionType, Code));
			if (IdNode == null) return null;

			var Ch = new ExpressionNode[] { IdNode };
			var Node = Plugin.NewNode(new OpExpressionNode(Operator.NewObject, Ch, Code));
			if (Node == null) return null;

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

		public static ExpressionNode Throw(PluginRoot Plugin, ExpressionNode Node,
			CodeString Code, bool End = true)
		{
			var Global = Plugin.Container.GlobalContainer;
			var Func = Identifiers.GetByFullNameFast<Function>(Global, "Internals.ThrowException");
			if (Func == null) return null;

			Node = Expressions.Call(Code, Plugin, Func, Node);
			return Node == null || !End ? Node : Plugin.End(Node);
		}

		public static ExpressionNode Negate(PluginRoot Plugin, ExpressionNode Node, CodeString Code, bool End = false)
		{
			var Ch = new ExpressionNode[] { Node };
			Node = Plugin.NewNode(new OpExpressionNode(Operator.Not, Ch, Code));
			if (Node == null) return null;

			if (End  && Plugin.End(ref Node) == PluginResult.Failed)
				return null;

			return Node;
		}

		public static ExpressionNode IsInRange(PluginRoot Plugin, ExpressionNode Node,
			NonFloatType Type, CodeString Code)
		{
			if (Node.InterrupterPlugin != -1 && Node.Type == null)
			{
				Node = Plugin.FinishNode(Node);
				if (Node == null) return null;
			}

			var NodeType = Node.Type.RealId as NonFloatType;
			var Min = BigInteger.Max(Type.MinValue, NodeType.MinValue);
			var Max = BigInteger.Min(Type.MaxValue, NodeType.MaxValue);
			return IsInRange(Plugin, Node, Min, Max, Code);
		}

		public static ExpressionNode IsInRange(PluginRoot Plugin, ExpressionNode Node,
			BigInteger Min, BigInteger Max, CodeString Code)
		{
			if (!(Node.Type.RealId is NonFloatType))
				throw new ArgumentException("Node");

			var MinValue = new IntegerValue(Min);
			var MaxValue = new IntegerValue(Max);
			return IsInRange(Plugin, Node, MinValue, MaxValue, Code);
		}

		public static ExpressionNode IsInRange(PluginRoot Plugin, ExpressionNode Node,
			ConstValue Min, ConstValue Max, CodeString Code)
		{
			var MinNode = Plugin.NewNode(new ConstExpressionNode(Node.Type, Min, Code));
			var MaxNode = Plugin.NewNode(new ConstExpressionNode(Node.Type, Max, Code));
			if (MinNode == null || MaxNode == null) return null;

			return IsInRange(Plugin, Node, MinNode, MaxNode, Code);
		}

		public static ExpressionNode IsInRange(PluginRoot Plugin, ExpressionNode Node,
			ExpressionNode Min, ExpressionNode Max, CodeString Code)
		{
			var Nodes = new ExpressionNode[] { Min, Node, Max };
			var Operators = new Operator[] { Operator.LessEqual, Operator.LessEqual };
			return Expressions.ChainedRelation(Plugin, Nodes, Operators, Code);
		}

		public static NonFloatType GetEquivalentNumberType(Identifier Id)
		{
			var Global = Id.Container.GlobalContainer;
			var Type = Id.RealId as Type;

			if (Type is EnumType)
			{
				var EType = Type as EnumType;
				Type = EType.TypeOfValues;
			}

			if (Type is NonFloatType) return Type as NonFloatType;
			if (Type is CharType) return Global.CommonIds.UInt16;
			if (Type is PointerType) return Global.CommonIds.GetIdentifier<UnsignedType>(Type.Size);
			return null;
		}

		public static NCExpressionRunBefores[] GetCommandRunBefores(Command Command)
		{
            var Ret = new NCExpressionRunBefores[Command.Expressions.Count];
            for (var i = 0; i < Command.Expressions.Count; i++)
                Ret[i] = GetExpressionRunBefores(Command, Command.Expressions[i]);

            return Ret;
		}

        public static void GetUsedCommandIdentifiers(Command Command, ExpressionNode Node, List<Identifier> Out)
        {
			if (Command.Children.Count == 0 && Command.IdentifierList.Count == 0)
				return;

            Node.ForEach(x =>
            {
                if (x is IdExpressionNode)
                {
                    var Idx = x as IdExpressionNode;
                    var IdContainer = Idx.Identifier.Container;
                    if (IdContainer == Command || IdContainer.IsSubContainerOf(Command))
                        Out.Add(Idx.Identifier);
                }
            });
        }

        public static Identifier[] GetUsedCommandIdentifiers(Command Command, ExpressionNode Node)
        {
            var List = new List<Identifier>();
            GetUsedCommandIdentifiers(Command, Node, List);
            return List.ToArray();
        }

        public static NCNeededRunBefore GetNeededRunBefore(Command Command, ExpressionNode Node)
        {
            //var Identifiers = GetUsedCommandIdentifiers(Command, Node);
            return new NCNeededRunBefore(Node/*, Identifiers*/);
        }

        public static void GetExpressionRunBefores(Command Command, ExpressionNode Node, List<NCNeededRunBefore> Out)
        {
            for (var i = 0; i < Node.LinkedNodes.Count; i++)
                GetExpressionRunBefores(Command, Node.LinkedNodes[i].Node, Out);

            if (Node.Children != null)
            {
                for (var i = 0; i < Node.Children.Length; i++)
                    GetExpressionRunBefores(Command, Node.Children[i], Out);
            }

            if (Node is OpExpressionNode)
            {
                var OpNode = Node as OpExpressionNode;
                var Op = OpNode.Operator;
                var Ch = OpNode.Children;

                if (Op == Operator.Cast)
                {
                    if (Node.CheckingMode == CheckingMode.Checked)
                    {
                        var NFrom = GetEquivalentNumberType(Ch[0].Type);
                        var NTo = GetEquivalentNumberType(Node.Type);
                        if (NFrom != null && NTo != null)
                        {
                            if (NFrom.Size > NTo.Size || (NFrom is SignedType && NTo is UnsignedType))
                                Out.Add(GetNeededRunBefore(Command, Ch[0]));
                        }
                    }
                }
                else if (IsOverflowableOp(Op))
                {
                    if (Node.CheckingMode == CheckingMode.Checked)
                    {
                        if (GetEquivalentNumberType(Node.Type) != null)
                            Out.Add(GetNeededRunBefore(Command, Node));
                    }
                }
                else if (Operators.IsNewOp(Op))
                {
                    if (!Node.LinkedNodes.TrueForAll(x => !(x.Node is InitializationNode)))
                    {/*
                        var IdList = new List<Identifier>();
                        for (var i = 0; i < Node.LinkedNodes.Count; i++)
                        {
                            var LNode = Node.LinkedNodes[i].Node;
                            if (LNode is InitializationNode)
                                LNode.ForEachChildren(x => GetUsedCommandIdentifiers(Command, x, IdList));
                        }
                        */
                        Out.Add(new NCNeededRunBefore(Node/*, IdList.ToArray()*/));
                    }
                }
            }
        }

        public static NCExpressionRunBefores GetExpressionRunBefores(Command Command, ExpressionNode Node)
		{
            var Ret = new NCExpressionRunBefores();
            var List = new List<NCNeededRunBefore>();
            GetExpressionRunBefores(Command, Node, List);
            Ret.NeededRunBefores = List.ToArray();
            return Ret;
		}
	}
}

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