using System;
using System.Linq;
using System.Collections.Generic;
using System.Numerics;
namespace Anonymus
{
public enum ExprRecognizerRes
{
UnknownOp,
DontCallNewNode,
Succeeded,
Failed,
}
public abstract class ExprRecognizer
{
public string[] Operators;
public string[] Skip;
public string[] NewLineLeft;
public string[] NewLineRight;
public string[] OnlyLeft;
public string[] OnlyRight;
static string[] GetStrings(string[] Array, string[] Skip)
{
var RetList = new List<string>();
foreach (var e in Array)
{
var Ok = true;
if (Skip != null)
{
foreach (var f in Skip)
if (f.Contains(e))
{
Ok = false;
break;
}
}
if (Ok) RetList.Add(e);
}
if (RetList.Count == 0) return null;
else return RetList.ToArray();
}
public virtual void Init()
{
if (NewLineLeft != null)
OnlyLeft = GetStrings(NewLineLeft, NewLineRight);
if (NewLineRight != null)
OnlyRight = GetStrings(NewLineRight, NewLineLeft);
}
public virtual ExprRecognizerRes Recognize(PString Code, ExprPlugIn PlugIn, ref ExpressionNode Ret)
{
return ExprRecognizerRes.UnknownOp;
}
public virtual T GetRecognizer<T>() where T : ExprRecognizer
{
if (this is T) return this as T;
else return null;
}
}
public abstract class ArgRecognizer : ExprRecognizer
{
public abstract bool SplitArgs(CompilerState State, PString Self, List<PString> Ret, bool EnableMessages = true);
}
public delegate ExpressionNode BEFunc();
public delegate ExpressionNode ExtractTupleOpFunc(int Index, List<ExpressionNode> Ch);
public static class Expressions
{
public static ExpressionNode ExtractTupleOp(ExpressionNode Node, ExprPlugIn PlugIn, ExtractTupleOpFunc Func, bool[] AlwaysLink = null)
{
var DstType = Node.Type.RealType as TupleType;
var NewCh = new List<ExpressionNode>();
var LinkedNodes = new List<LinkedExprNode>();
var Index = 0;
foreach (var Ch in Node.EnumChildren)
{
var OpCh = Ch as OpExpressionNode;
if (OpCh == null || OpCh.Operator != Operator.CreateTuple || (AlwaysLink != null && AlwaysLink[Index]))
{
LinkedNodes.Add(new LinkedExprNode(Ch));
continue;
}
LinkedNodes.Add(null);
Index++;
}
Index = 0;
foreach (MemberVariable Member in DstType.Members)
{
var Args = new List<ExpressionNode>();
var ArgIndex = 0;
foreach (var Ch in Node.EnumChildren)
{
if (LinkedNodes[ArgIndex] != null)
{
var SrcType = Ch.Type.RealType as TupleType;
var Linking = PlugIn.NewNode(new LinkingNode(LinkedNodes[ArgIndex], Node.Code));
var MNode = PlugIn.NewNode(new IdExpressionNode(SrcType.Members[Index], Node.Code));
if (MNode == null || Linking == null) return null;
var MemberCh = new List<ExpressionNode>() { Linking, MNode };
var MemberOp = PlugIn.NewNode(new OpExpressionNode(Operator.Member, MemberCh, Node.Code));
if (MemberOp == null) return null;
Args.Add(MemberOp);
}
else
{
var OpCh = Ch as OpExpressionNode;
Args.Add(OpCh.Children[Index]);
}
ArgIndex++;
}
var Ret = Func(Index, Args);
if (Ret == null) return null;
NewCh.Add(Ret);
Index++;
}
Node = new OpExpressionNode(Operator.CreateTuple, NewCh, Node.Code);
if (LinkedNodes != null)
{
LinkedNodes.RemoveAll(x => x == null);
Node.LinkedNodes = LinkedNodes;
}
Node.Type = DstType;
Node = PlugIn.NewNode(Node);
return Node;
}
public static ExpressionNode CreateConstNode(PString Code,
ConstData Data, Type Type, ExprPlugIn PlugIn = null)
{
var Ret = new ConstExpressionNode(Type, Data, Code);
if (PlugIn == null) return Ret;
else return PlugIn.NewNode(Ret);
}
public static ExpressionNode CreateCallIndexExpr(PString Code, ExprPlugIn PlugIn,
Operator Op, PString FuncName, ExpressionNode Ch)
{
return CreateCallIndexExpr(Code, PlugIn, Op, FuncName, Helper.ObjToEnumable(Ch));
}
public static ExpressionNode CreateCallIndexExpr(PString Code, ExprPlugIn PlugIn,
Operator Op, List<ExpressionNode> Ch)
{
var OpNode = new OpExpressionNode(Op, Ch, Code);
return PlugIn.NewNode(OpNode);
}
public static ExpressionNode CreateCallIndexExpr(PString Code, ExprPlugIn PlugIn,
Operator Op, PString FuncName, PString Params)
{
var Ch = CreateParamNodes(PlugIn, Code, FuncName, Params);
if (Ch == null) return null;
return CreateCallIndexExpr(Code, PlugIn, Op, Ch);
}
public static ExpressionNode CreateCallIndexExpr(PString Code, ExprPlugIn PlugIn, Operator Op, List<PString> Params)
{
var Ch = CreateParamNodes(PlugIn, Code, Params);
if (Ch == null) return null;
return CreateCallIndexExpr(Code, PlugIn, Op, Ch);
}
public static ExpressionNode CreateCallIndexExpr(PString Code, ExprPlugIn PlugIn,
Operator Op, PString FuncName, IEnumerable<ExpressionNode> Ch)
{
var Func = Recognize(FuncName, PlugIn, false);
if (Func == null) return null;
var NewCh = new List<ExpressionNode>() { Func };
NewCh.AddRange(Ch);
return CreateCallIndexExpr(Code, PlugIn, Op, NewCh);
}
public static ExpressionNode GetId(ExprPlugIn PlugIn, PString Code, IdContainer Container = null)
{
if (Container == null) Container = PlugIn.Container;
var Node = Container.GetExprRec(Code, PlugIn: PlugIn);
if (Node == null)
{
var Var = Container.GetId<Identifier>(Code, EnableMessages: false);
if (Var == null) return PlugIn.NewNode(new StrExpressionNode(Code));
Node = PlugIn.NewNode(new IdExpressionNode(Var, Code));
}
if (Node is IdExpressionNode)
{
var RIdNode = Node as IdExpressionNode;
if (RIdNode.Id is MemberVariable || RIdNode.Id is MemberFunction)
{
var Var = RIdNode.Id as MemberVariable;
var Self = PlugIn.Container.FuncScope.Self;
if (Self != null)
{
var RIdSelf = PlugIn.NewNode(new IdExpressionNode(Self, Code));
if (RIdSelf == null) return null;
var Ch = new List<ExpressionNode>() { RIdSelf, RIdNode };
return PlugIn.NewNode(new OpExpressionNode(Operator.Member, Ch, Code));
}
return PlugIn.NewNode(new StrExpressionNode(Code));
}
else if (RIdNode.Id is ConstructorFunction)
{
if (Container.Parent == null) throw new Exception("ERROR");
return GetId(PlugIn, Code, Container.Parent);
}
}
return Node;
}
public static int AsFindParamPosition(CompilerState State, string Line)
{
var ZHlp = new BracketHelper();
var Ok = false;
for (var i = 0; i < Line.Length; i++)
{
var Chr = Line[i];
if (!ZHlp.OnChar(Chr)) continue;
if (!StringHelper.IsIdChar(Chr))
{
if (!Ok) continue;
else if (Chr == '(') return -1;
var C = StringHelper.LWhiteSpaceCount(Line, i + 1);
var Pos = i + C + 1;
if (Pos >= 0 && char.IsWhiteSpace(Chr) && StringHelper.IsIdChar(Line[Pos]))
return i;
var Rec = State.Language.ExprRecognizer;
if (Line.SubstringEquals(i, Rec.OnlyRight).Position != -1)
return i;
}
else
{
Ok = true;
}
}
return -1;
}
public static ExpressionNode CreateFuncCallNode(PString Line, ExprPlugIn PlugIn)
{
var State = PlugIn.State;
var Pos = AsFindParamPosition(PlugIn.State, Line.String);
if (Pos != -1)
{
var str_Func = Line.TrimmedSubstring(0, Pos);
var str_Params = BracketHelper.TrimOneBracket(Line.TrimmedSubstring(Pos));
BEFunc Func = () =>
{
return CreateCallIndexExpr(Line, PlugIn, Operator.Call, str_Func, str_Params);
};
return BeginEnd(PlugIn, Func);
}
else
{
var Node = NewExpressionTree(Line, PlugIn, false);
if (Node == null) return null;
var OpNode = Node as OpExpressionNode;
if (OpNode == null || OpNode.Operator != Operator.Call)
{
var Ch = new List<ExpressionNode>() { Node };
Node = PlugIn.NewNode(new OpExpressionNode(Operator.Call, Ch, Line));
if (Node == null) return null;
}
return PlugIn.End(Node);
}
}
public static FindRes Find2(CompilerState State, string String, string[] Find, string[] Skip = null)
{
var Start = String.Length - 1;
FindRes Result;
while (true)
{
if (Start >= 0)
{
Result = String.Find(Find, InZ: true, Start: Start, Skip: Skip, Back: true);
if (Result.Position != -1)
{
var Str = String.Substring(0, Result.Position).Trim();
Start = Result.Position - Result.String.Length;
var FindS = State.Language.ExprRecognizer.Operators;
if (Str == "" || Str.EndsWith(FindS, NotIdChar: true).Position != -1)
continue;
else break;
}
}
Result = new FindRes(-1, -1, null);
break;
}
return Result;
}
public static bool IsCastString(CompilerState State, string String)
{
if (String[0] == '(')
{
var ZPos = BracketHelper.ZPos(String);
if (ZPos == -1) return false;
String = String.Substring(ZPos + 1).Trim();
var FindS = State.Language.ExprRecognizer.NewLineLeft;
if (String.StartsWith(FindS, NotIdChar: true).Position != -1)
return false;
return true;
}
return false;
}
public static List<ExpressionNode> TwoParamOpNode(PString String, FindRes Result, ExprPlugIn PlugIn)
{
var NStr = String.TrimmedSubstring(0, Result.Position);
var MStr = String.TrimmedSubstring(Result.Position + Result.String.Length);
if (NStr.String == "" || MStr.String == "")
{
PlugIn.State.Messages.Add(MessageId.DeficientExpr, String);
return null;
}
var N = Recognize(NStr, PlugIn, true);
var M = Recognize(MStr, PlugIn, true);
if (N == null || M == null) return null;
else return new List<ExpressionNode>() { N, M };
}
static PString ChkTrmSubStr(CompilerState State, PString String, int StrSize = 1, bool Back = false)
{
PString Ret;
if (!Back) Ret = String.TrimmedSubstring(StrSize);
else Ret = String.TrimmedSubstring(0, String.StrLen - StrSize);
if (Ret.String == "")
{
State.Messages.Add(MessageId.DeficientExpr, String);
return null;
}
return Ret;
}
public static ExpressionNode OneParamOpNode(PString String, ExprPlugIn Settings,
Operator Op, int StrSize = 1)
{
var ps = ChkTrmSubStr(Settings.State, String, StrSize);
var Node = Recognize(ps, Settings, true);
if (Node != null) return new OpExpressionNode(Op, new List<ExpressionNode>() { Node }, String);
else return null;
}
public static ExpressionNode NewExpressionTree(PString String, ExprPlugIn PlugIn, bool End = true)
{
BEFunc Func = () => { return Recognize(String, PlugIn, false); };
return BeginEnd(PlugIn, Func, End);
}
public static ExpressionNode BeginEnd(ExprPlugIn PlugIn, BEFunc Func, bool End = true)
{
if (!PlugIn.Begin()) return null;
var Ret = Func();
if (End && Ret != null) Ret = PlugIn.End(Ret);
return Ret;
}
public static ConstExpressionNode GetIntValue(IdContainer Container, int Val, PString Code)
{
var IntType = Container.GetType(typeof(SignedType), 4);
return new ConstExpressionNode(IntType, Val, Code);
}
public static ConstExpressionNode GetFloatValue(IdContainer Container, double Val, PString Code)
{
var FloatType = Container.GetType(typeof(FloatType), 8);
return new ConstExpressionNode(FloatType, Val, Code);
}
public static ExpressionNode IncDecNode(PString String,
ExprPlugIn PlugIn, Operator Op, int StrSize)
{
var Str = ChkTrmSubStr(PlugIn.State, String, StrSize, Back: true);
if (Str != null)
{
var RId = Recognize(Str, PlugIn, true);
var One = PlugIn.NewNode(GetIntValue(PlugIn.Container, 1, String));
if (RId != null && One != null)
{
var Addition = PlugIn.NewNode(new OpExpressionNode(Op, new List<ExpressionNode>() { RId, One }, String));
if (Addition != null)
{
var Ch = new List<ExpressionNode>() { RId, Addition };
return PlugIn.NewNode(new OpExpressionNode(Operator.Assignment, Ch, String));
}
}
}
return null;
}
public static ExpressionNode Recognize(PString Code, ExprPlugIn PlugIn, bool Trimmed)
{
if (!Trimmed)
{
Code.TrimThis();
}
#if DEBUG
else if (Code.String.LWhiteSpaceCount() != 0 ||
Code.String.RWhiteSpaceCount() != 0)
{
throw new Exception("Not Trimmed");
}
if (Code == null || Code.String == "")
throw new Exception("Deficient");
#endif
var Recognizer = PlugIn.Recognizer;
var State = PlugIn.State;
var RetValue = (ExpressionNode)null;
var NewCode = BracketHelper.TrimFZ(Code);
if (NewCode.StrLen == 0)
{
State.Messages.Add(MessageId.DeficientExpr, Code);
return null;
}
var Res = Recognizer.Recognize(NewCode, PlugIn, ref RetValue);
if (Res == ExprRecognizerRes.Succeeded)
{
RetValue = PlugIn.NewNode(RetValue);
if (RetValue == null) return null;
}
else if (Res == ExprRecognizerRes.UnknownOp)
{
State.Messages.Add(MessageId.UnknownOp, NewCode);
return null;
}
else if (Res == ExprRecognizerRes.Failed)
{
return null;
}
return RetValue;
}
public static List<PString> ConstructCallIndexParams(CompilerState State, PString Func, PString Params)
{
var Ret = new List<PString>();
if (Func != null) Ret.Add(Func);
Params = Params.Trim();
if (Params.StrLen == 0) return Ret;
var Recognizer = State.Language.ArgRecognizer;
if (!Recognizer.SplitArgs(State, Params, Ret))
return null;
return Ret;
}
public static List<ExpressionNode> CreateParamNodes(ExprPlugIn PlugIn, PString Code,
PString Func, PString Params, int ParamCount = -1)
{
var Lst = ConstructCallIndexParams(PlugIn.State, Func, Params);
if (Lst == null) return null;
return CreateParamNodes(PlugIn, Code, Lst, ParamCount);
}
public static List<ExpressionNode> CreateParamNodes(ExprPlugIn PlugIn, PString Code,
IEnumerable<PString> Params, int ParamCount = -1)
{
var Nodes = new List<ExpressionNode>();
foreach (var Obj in Params)
{
var Node = Recognize(Obj, PlugIn, true);
if (Node == null) return null;
Nodes.Add(Node);
}
if (ParamCount != -1 && Nodes.Count != ParamCount)
{
PlugIn.State.Messages.Add(MessageId.ParamCount, Code);
return null;
}
return Nodes;
}
public static ConstExpressionNode GetBoolValue(BoolType Type, bool Value, PString Code)
{
var Val = Value ? Type.TrueVal : Type.FalseVal;
return new ConstExpressionNode(Type, Val, Code);
}
public static ConstExpressionNode GetBoolValue(IdContainer Container, bool Value, PString Code)
{
var Tp = Container.GlobalScope.BoolType as BoolType;
return GetBoolValue(Tp, Value, Code);
}
public static bool IsLiteral(string Code)
{
var f = Code[0];
if (Code == "true" || Code == "false" || Code == "pi" || Code == "null")
return true;
if (char.IsDigit(f) || f == '$' || f == '%' || f == '-')
{
if (f == '-') Code = Code.Substring(1).Trim();
f = Code[0];
Code = f == '$' || f == '%' ? Code.Substring(1) : Code;
var Old = Code;
Code = StringHelper.CutEndStr(Code, LetterCase.Lower);
if (Code.Length == 0) Code = Old;
var P = Code.IndexOf(".");
if (P == -1) return Code.IsNum();
return Code.Substring(0, P).IsNum() &&
Code.Substring(P + 1).IsNum();
}
if (f == '\"' && Code.Length > 1 && Code[Code.Length - 1] == '\"')
if (Code.Substring(1, Code.Length - 2).IndexOf('\"') == -1)
return true;
return false;
}
public static ConstExpressionNode GetLiteral(ExprPlugIn PlugIn, PString Code)
{
var Container = PlugIn.Container;
var State = PlugIn.State;
var FStr = Code.Copy();
if (Code.String == "true") return GetBoolValue(Container, true, FStr);
if (Code.String == "false") return GetBoolValue(Container, false, FStr);
if (Code.String == "pi") return Expressions.GetFloatValue(Container, Math.PI, Code) as ConstExpressionNode;
if (Code.String == "null") return new ConstExpressionNode(Container.GlobalScope.AutoType, 0, Code);
var FirstChar = Code[0];
if (FirstChar == '\"' && Code.StrLen > 1 && Code[Code.StrLen -1] == '\"')
{
var s = Code.Substring(1, Code.StrLen - 2).String;
if (s.IndexOf('\"') == -1) return new ConstExpressionNode(Container.GlobalScope.CStrType, s, FStr);
}
if (char.IsDigit(FirstChar) || FirstChar == '$' || FirstChar == '%' || FirstChar == '-')
{
var Str = Code.String;
var Type = (Type)null;
var End = StringHelper.EndStr(Code.String, LetterCase.Lower);
if (!string.IsNullOrEmpty(End))
{
foreach (var Id in Container.GlobalScope.BasicTypes)
{
var Tp = Id as NumberType;
if (Tp != null && Tp.Code == End)
{
Str = Str.Substring(0, Str.Length - Tp.Code.Length);
Type = Tp;
}
}
if (Type == null)
{
State.Messages.Add(MessageId.UnknownType, Code);
return null;
}
}
var Neg = FirstChar == '-';
if (Neg) Str = Str.Substring(1).Trim();
FirstChar = Str[0];
var S = 10;
if (!char.IsDigit(FirstChar))
{
if (FirstChar == '$')
{
S = 16;
Str = Str.Substring(1);
}
else if (FirstChar == '%')
{
S = 2;
Str = Str.Substring(1);
}
else
{
State.Messages.Add(MessageId.ConstNumErr, Code);
return null;
}
}
return ConvStrToConst(State, Code, Str, Type, Container, S, Neg);
}
return null;
}
public static ConstExpressionNode ConvStrToConst(CompilerState State, PString Code, string Num, Type Type = null,
IdContainer Container = null, int Radix = 10, bool Negative = false)
{
var P = Num.IndexOf(".");
if (P == -1)
{
BigInteger Ret;
if (!Num.ConvertToDec(Radix, LetterCase.Upper, out Ret))
{
State.Messages.Add(MessageId.ConstNumErr, Code);
return null;
}
if (Negative) Ret = -Ret;
if (Type == null) Type = Container.GetType(typeof(SignedType), 4);
if (Type is FloatType)
{
return new ConstExpressionNode(Type, (double)Ret, Code);
}
else if (Type is NonFltNumType)
{
var NFltTp = Type as NonFltNumType;
if (Ret <= NFltTp.MaxValue && Ret >= NFltTp.MinValue)
{
if (NFltTp is SignedType)
return new ConstExpressionNode(Type, (long)Ret, Code);
else if (NFltTp is UnsignedType)
return new ConstExpressionNode(Type, (ulong)Ret, Code);
else throw new Exception("ERROR");
}
}
}
else
{
var Str1 = Num.Substring(0, P);
var Str2 = Num.Substring(P + 1);
BigInteger N1, N2;
if (!Str1.ConvertToDec(Radix, LetterCase.Upper, out N1) ||
!Str2.ConvertToDec(Radix, LetterCase.Upper, out N2))
{
State.Messages.Add(MessageId.ConstNumErr, Code);
return null;
}
var Dbl = (double)N1 + (double)N2 / (double)(Str2.Length * Radix);
if (Negative) Dbl = -Dbl;
if (Type == null) Type = Container.GetType(typeof(FloatType), 8);
if (Type is FloatType) return new ConstExpressionNode(Type, Dbl, Code);
}
State.Messages.Add(MessageId.ConstOutOfRange, Code);
return null;
}
public static ConstExpressionNode GetStringNode(PString Code, IdContainer Container)
{
var GlbScope = Container.GlobalScope;
var PlugIn = new GlobalPlugIn(Container);
PlugIn.GetPlugIn<TypeMgrPlugIn>().RetType = GlbScope.CStrType;
return Expressions.NewExpressionTree(Code, PlugIn) as ConstExpressionNode;
}
}
}