using System;
using System.Collections.Generic;
using NTERA.EmuEra.Game.EraEmu.GameData.Expression;
using NTERA.EmuEra.Game.EraEmu.GameData.Variable;
using NTERA.EmuEra.Game.EraEmu.GameProc.Function;
using NTERA.EmuEra.Game.EraEmu.Sub;
namespace NTERA.EmuEra.Game.EraEmu.GameProc
{
///
/// 命令文1行に相当する抽象クラス
///
internal abstract class LogicalLine
{
protected ScriptPosition position;
//LogicalLine prevLine;
LogicalLine nextLine;
public ScriptPosition Position => position;
public FunctionLabelLine ParentLabelLine { get; set; }
public LogicalLine NextLine
{
get => nextLine;
set { nextLine = value; }
}
public override string ToString()
{
if (position == null)
return base.ToString();
return string.Format("{0}:{1}:{2}", position.Filename, position.LineNo, position.RowLine);
}
protected bool isError;
protected string errMes = "";
public virtual string ErrMes
{
get => errMes;
set { errMes = value; }
}
public virtual bool IsError
{
get => isError;
set { isError = value; }
}
}
/////
///// コメント行。
/////
//internal sealed class CommentLine : LogicalLine
//{
// public CommentLine(ScriptPosition thePosition, string str)
// {
// base.position = thePosition;
// //comment = str;
// }
// //string comment;
// public override bool IsError
// {
// get { return false; }
// }
//}
///
/// 無効な行。
///
internal sealed class InvalidLine : LogicalLine
{
public InvalidLine(ScriptPosition thePosition, string err)
{
position = thePosition;
errMes = err;
}
public override bool IsError => true;
}
///
/// 命令文
///
internal sealed class InstructionLine : LogicalLine
{
public InstructionLine(ScriptPosition thePosition, FunctionIdentifier theFunc, StringStream theArgPrimitive)
{
position = thePosition;
func = theFunc;
argprimitive = theArgPrimitive;
}
public InstructionLine(ScriptPosition thePosition, FunctionIdentifier functionIdentifier, OperatorCode assignOP, WordCollection dest, StringStream theArgPrimitive)
{
position = thePosition;
func = functionIdentifier;
AssignOperator = assignOP;
assigndest = dest;
argprimitive = theArgPrimitive;
}
readonly FunctionIdentifier func;
StringStream argprimitive;
WordCollection assigndest;
public OperatorCode AssignOperator { get; private set; }
Int64 subData;
public FunctionCode FunctionCode => func.Code;
public FunctionIdentifier Function => func;
public Argument Argument { get; set; }
public StringStream PopArgumentPrimitive()
{
StringStream ret = argprimitive;
argprimitive = null;
return ret;
}
public WordCollection PopAssignmentDestStr()
{
WordCollection ret = assigndest;
assigndest = null;
return ret;
}
///
/// 繰り返しの終了を記憶する
///
public Int64 LoopEnd
{
get => subData;
set { subData = value; }
}
VariableTerm cnt;
///
/// 繰り返しにつかう変数を記憶する
///
public VariableTerm LoopCounter
{
get => cnt;
set { cnt = value; }
}
Int64 step;
///
/// 繰り返しのたびに増加する値を記憶する
///
public Int64 LoopStep
{
get => step;
set { step = value; }
}
private LogicalLine jumpto;
private LogicalLine jumptoendcatch;
//IF文とSELECT文のみが使う。
public List IfCaseList = null;
//PRINTDATA文のみが使う。
public List> dataList = null;
//TRYCALLLIST系が使う
public List callList = null;
public LogicalLine JumpTo
{
get => jumpto;
set { jumpto = value; }
}
public LogicalLine JumpToEndCatch
{
get => jumptoendcatch;
set { jumptoendcatch = value; }
}
}
///
/// ファイルの始端と終端
///
internal sealed class NullLine : LogicalLine { }
///
/// ラベルがエラーになっている関数行専用のクラス
///
internal sealed class InvalidLabelLine : FunctionLabelLine
{
public InvalidLabelLine(ScriptPosition thePosition, string labelname, string err)
{
position = thePosition;
LabelName = labelname != null ? String.Intern(labelname) : labelname;
errMes = err;
IsSingle = false;
Index = -1;
Depth = -1;
IsMethod = false;
MethodType = typeof(void);
}
public override bool IsError => true;
}
///
/// @で始まるラベル行
///
internal class FunctionLabelLine : LogicalLine, IComparable
{
protected FunctionLabelLine() { }
public FunctionLabelLine(ScriptPosition thePosition, string labelname, WordCollection wc)
{
position = thePosition;
LabelName = labelname != null ? String.Intern(labelname) : labelname;
IsSingle = false;
hasPrivDynamicVar = false;
Index = -1;
Depth = -1;
LocalLength = 0;
LocalsLength = 0;
ArgLength = 0;
ArgsLength = 0;
IsMethod = false;
MethodType = typeof(void);
this.wc = wc;
//ArgOptional = true;
//ArgAutoConvert = true;
}
WordCollection wc;
public WordCollection PopRowArgs()
{
WordCollection ret = wc;
wc = null;
return ret;
}
public string LabelName { get; protected set; }
public bool IsEvent { get; set; }
public bool IsSystem { get; set; }
public bool IsSingle { get; set; }
public bool IsPri { get; set; }
public bool IsLater { get; set; }
public bool IsOnly { get; set; }
public bool hasPrivDynamicVar { get; set; }
public int LocalLength { get; set; }
public int LocalsLength { get; set; }
public int ArgLength { get; set; }
public int ArgsLength { get; set; }
//public bool ArgOptional { get; set; }
//public bool ArgAutoConvert { get; set; }
public bool IsMethod { get; set; }
public Type MethodType { get; set; }
public VariableTerm[] Arg { get; set; }
public SingleTerm[] Def { get; set; }
//public SingleTerm[] SubNames { get; set; }
public int Depth { get; set; }
#region IComparable メンバ
//ソート用情報
public int Index { get; set; }
public int FileIndex { get; set; }
public int CompareTo(FunctionLabelLine other)
{
if (FileIndex != other.FileIndex)
return FileIndex.CompareTo(other.FileIndex);
//position == nullであるLine(デバッグコマンドなど)をSortすることはないはず
if (position.LineNo != other.position.LineNo)
return position.LineNo.CompareTo(other.position.LineNo);
return Index.CompareTo(other.Index);
}
#endregion
#region private変数
Dictionary privateVar = new Dictionary();
internal bool AddPrivateVariable(UserDefinedVariableData data)
{
if (privateVar.ContainsKey(data.Name))
return false;
UserDefinedVariableToken var = GlobalStatic.VariableData.CreatePrivateVariable(data);
privateVar.Add(data.Name, var);
//静的な変数のみの場合は関数呼び出し時に何もする必要がない
if (!data.Static)
hasPrivDynamicVar = true;
return true;
}
internal UserDefinedVariableToken GetPrivateVariable(string key)
{
UserDefinedVariableToken var = null;
privateVar.TryGetValue(key, out var);
return var;
}
///
/// 引数の値の確定後、引数の代入より前に呼ぶこと
///
internal void In()
{
#if DEBUG
GlobalStatic.StackList.Add(this);
#endif
foreach (UserDefinedVariableToken var in privateVar.Values)
if (!var.IsStatic)
var.In();
}
internal void Out()
{
#if DEBUG
GlobalStatic.StackList.Remove(this);
#endif
foreach (UserDefinedVariableToken var in privateVar.Values)
if (!var.IsStatic)
var.Out();
}
#endregion
}
///
/// $で始まるラベル行
///
internal sealed class GotoLabelLine : LogicalLine, IEqualityComparer
{
public GotoLabelLine(ScriptPosition thePosition, string labelname)
{
position = thePosition;
this.labelname = String.Intern(labelname);
}
readonly string labelname = "";
public string LabelName => labelname;
#region IEqualityComparer メンバ
public bool Equals(GotoLabelLine x, GotoLabelLine y)
{
if ((x == null) || (y == null))
return false;
return ((x.ParentLabelLine == y.ParentLabelLine) && (x.labelname == y.labelname));
}
public int GetHashCode(GotoLabelLine obj)
{
return labelname.GetHashCode() ^ ParentLabelLine.GetHashCode();
}
#endregion
}
}