using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace Anonymus
{
public abstract class CodeProcessor
{
public abstract bool Process(CodeScopeNode Scope);
}
public class CodeScopeNode : ScopeNode
{
public List<Command> Commands = new List<Command>();
public bool AllPathJumpAway;
public override IEnumerable<IdContainer> EnumChildren
{
get
{
return Commands.Union(base.EnumChildren);
}
}
public IEnumerable<CodeScopeNode> EnumScopes
{
get
{
foreach (var Command in Commands)
foreach (var e in Command.EnumScopes)
yield return e;
}
}
public override Variable CreateVariable(PString Name, Type Type, ModifierList Mods = null)
{
var Ret = new LocalVariable(this, Name, Type);
if (Mods != null && !Mods.Apply(this, Ret)) return null;
return Ret;
}
public override bool FinishCodeChk()
{
var Ret = base.FinishCodeChk();
var Unreachable = false;
foreach (var Comm in Commands)
if (Unreachable != Comm.Unreachable && Comm.ChkUnreachable)
{
Unreachable = Comm.Unreachable;
if (Unreachable) State.Messages.Add(MessageId.UnreacheableCode, Comm.Code);
}
return Ret;
}
public override bool ChkCodeRec(CodeChkData Data, ref bool Succeeded)
{
return ChkCodeRec(Data, 0, ref Succeeded);
}
public bool ChkCodeRec(CodeChkData Data, int StartIndex, ref bool Succeeded)
{
base.ChkCodeRec(Data, ref Succeeded);
for (var i = StartIndex; i < Commands.Count; i++)
if (Commands[i].ChkCodeRec(Data, ref Succeeded))
{
AllPathJumpAway = true;
return true;
}
return false;
}
public override MultiPlugIn GetPlugIn()
{
return new LocalPlugIn(this);
}
public override void InitCodeChk(bool Unreachable = true)
{
AllPathJumpAway = false;
base.InitCodeChk(Unreachable);
}
public CodeScopeNode(IdContainer Parent, PString[] Source)
: base(Parent, Source)
{
}
public bool AddCommand(PString Code, Command Comm, bool ChkUnreachable = true)
{
var LComm = LastCommand;
if (LComm!= null)
{
if (LComm is WhileCommand)
{
var C = LComm as WhileCommand;
if (C.DoWhile && C.Condition == null)
{
State.Messages.Add(MessageId.MustWhile, LComm.Code);
Commands.RemoveAt(Commands.Count - 1);
return false;
}
}
else if (LComm is SwitchCommand)
{
var Switch = LComm as SwitchCommand;
if (Switch.Conditions.Count == 0)
{
State.Messages.Add(MessageId.SwitchNoCaseDef, Switch.Code);
return false;
}
}
}
Comm.CommIndex = Commands.Count;
Comm.Code = Code;
Comm.ChkUnreachable = ChkUnreachable;
Commands.Add(Comm);
return true;
}
public bool AddExpressionCommand(PString Line, ExpressionNode Node, bool ChkUnreachable = true)
{
return AddCommand(Line, CreateExpressionCommand(Node), ChkUnreachable);
}
public EmptyCommand CreateEmptyCommand()
{
var Ret = new EmptyCommand(this);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public ExpressionCommand CreateExpressionCommand(ExpressionNode Node)
{
var Ret = new ExpressionCommand(this, Node);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public LabelCommand CreateLabelCommand(int Label)
{
var Ret = new LabelCommand(this, Label);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public GotoCommand CreateGotoCommand(PString Label)
{
var Ret = new GotoCommand(this, Label);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public BreakCommand CreateBreakCommand(int Label)
{
var Ret = new BreakCommand(this, Label);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public ContinueCommand CreateContinueCommand(int Label)
{
var Ret = new ContinueCommand(this, Label);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public RetCommand CreateRetCommand(int Label, bool Chk)
{
var Ret = new RetCommand(this, Label, Chk);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public LoopCommand CreateLoopCommand()
{
var Ret = new LoopCommand(this);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public WhileCommand CreateWhileCommand(ExpressionNode Condition, bool DoWhile = false)
{
var Ret = new WhileCommand(this, Condition, DoWhile);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public ForCommand CreateForCommand(ExpressionNode Condition, ExpressionNode Loop, ExpressionNode Init)
{
var Ret = new ForCommand(this, Condition, Loop, Init);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public ConditionCommand CreateConditionCommand()
{
var Ret = new ConditionCommand(this);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public AsmCommand CreateAsmCommand()
{
var Ret = new AsmCommand(this);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public SwitchCommand CreateSwitchCommand()
{
var Ret = new SwitchCommand(this);
State.Arch.OnNewContainer(Ret);
return Ret;
}
public Command LastCommand
{
get
{
var CommCount = Commands.Count;
if (CommCount > 0) return Commands[CommCount - 1];
else return null;
}
}
public bool RecognizeCommand(PString Code, int LineIndex)
{
var FLine = Code.Copy();
var Line = Code.Copy();
var Word = Line.Word();
return RecognizeCommand(FLine, Word, Line, LineIndex);
}
public bool RecognizeCommand(PString Code, PString Word, PString Line, int LineIndex)
{
var Rec = State.Language.CommRecognizer;
var Res = Rec.Recognize(Code, Word, Line, LineIndex, this);
if (Res == CommRecognizerRes.Succeeded)
return true;
else if (Res == CommRecognizerRes.Failed)
return false;
else if (Res == CommRecognizerRes.UnknownOp)
{
State.Messages.Add(MessageId.NotExpected, Code);
return false;
}
else
throw new Exception("ERROR");
}
public bool CopyRetVal(PString Code)
{
var FuncScope = this.FuncScope;
if (FuncScope.TmpRetVal != null)
{
var PlugIn = GetPlugIn();
if (!PlugIn.Begin()) return false;
var SrcVar = PlugIn.NewNode(new IdExpressionNode(FuncScope.TmpRetVal, Code));
var DstVar = PlugIn.NewNode(new IdExpressionNode(FuncScope.RetVar, Code));
if (SrcVar == null || DstVar == null) return false;
var AssignmentCh = new List<ExpressionNode>() { DstVar, SrcVar };
var Assignment = PlugIn.NewNode(new OpExpressionNode(Operator.Assignment, AssignmentCh, Code));
if (Assignment == null) return false;
if ((Assignment = PlugIn.End(Assignment)) == null) return false;
if (!AddExpressionCommand(Code, Assignment)) return false;
}
return true;
}
public static bool NeedReturnVal(Type RetType)
{
if (RetType is VoidType) return false;
if (RetType is NamedFuncRetType) return false;
if (RetType is TupleType)
{
var Tuple = RetType as TupleType;
if (Tuple.Named) return false;
}
return true;
}
public virtual bool ProcessCode()
{
return State.Language.CodeProcessor.Process(this);
}
public virtual void GetAsmCode(Compiler Compiler)
{
Compiler.Container = this;
foreach (var e in Commands)
if (!e.Unreachable) e.GetAsmCode(Compiler);
}
public override bool DeclareVariables(List<Variable> Variables, GetIdMode IdMode = GetIdMode.Everywhere)
{
var Ret = base.DeclareVariables(Variables, IdMode);
foreach (var e in Variables)
if (e != null && e.InitValue != null && !AddExpressionCommand(e.InitString, e.InitValue))
Ret = false;
return Ret;
}
}
public enum GetAsmCodeMode
{
Code,
Data,
}
public abstract class FuncScopeNode : CodeScopeNode
{
public PString Name;
public FunctionType Type;
public string AsmCode;
public Dictionary<string, LabelCommand> Labels = new Dictionary<string, LabelCommand>();
public List<GotoCommand> Gotos = new List<GotoCommand>();
public LocalVariable Self;
public List<LocalVariable> Params;
public int RetLabel;
public LocalVariable RetVar;
public LocalVariable TmpRetVal;
public List<Identifier> RetMembers;
public abstract void CreateAsmCode();
public FuncScopeNode(IdContainer Parent, PString Name, FunctionType Type, bool IsStatic, PString[] Source)
: base(Parent, Source)
{
this.Type = Type;
this.Name = Name;
RetLabel = State.NextLabelIndex;
RetVar = new LocalVariable(this, new PString("__ret_value_"), Type.RetType);
RetVar.RetVar = true;
Params = new List<LocalVariable>();
foreach (var e in Type.Params)
{
var Var = new LocalVariable(this, e.Name, e.Type);
Var.PreAssigned = true;
Var.IsParameter = true;
Params.Add(Var);
}
if (Parent is StructuredTypeScope && !IsStatic)
{
var StructuredParent = Parent as StructuredTypeScope;
var SelfType = (Type)StructuredParent.Type;
if (SelfType is ValueType) SelfType = SelfType.CreateRefType();
Self = CreateVariable(new PString("this"), SelfType) as LocalVariable;
Self.ReadOnly = true;
Self.PreAssigned = true;
Params.Add(Self);
}
if (RetVar.Type is TupleType)
{
var Tuple = RetVar.Type as TupleType;
if (Tuple.Named)
{
RetMembers = new List<Identifier>();
foreach (MemberVariable e in Tuple.Members)
RetMembers.Add(new PackedMemberId(this, e.Name, e.Type, RetVar, e));
}
}
else if (RetVar.Type is NamedFuncRetType)
{
var Named = RetVar.Type as NamedFuncRetType;
var RType = Named.Child;
TmpRetVal = new LocalVariable(this, Named.Name, RType);
State.Arch.OnNewIdentifier(TmpRetVal);
}
}
public bool ProcessLabels()
{
var RetValue = true;
foreach (var Goto in Gotos)
{
var LblCmd = GetLabelCmd(Goto.LabelName.String);
if (LblCmd == null)
{
State.Messages.Add(MessageId.UnknownLabel, Goto.LabelName);
RetValue = false;
}
else
{
Goto.JumpTo = LblCmd;
Goto.Label = LblCmd.Label;
}
}
return RetValue;
}
public LabelCommand GetLabelCmd(string Name)
{
foreach (var e in Labels.Keys)
if (e == Name) return Labels[e];
return null;
}
public override T GetIdRec<T>(PString Name, GetIdMode Mode = GetIdMode.Everywhere,
bool SearchedInBasicTypes = false)
{
if (Name.String == "this" && Self != null)
return Self as T;
if (RetMembers != null)
{
foreach (var e in RetMembers)
if (e.Name.String == Name.String && e is T)
return e as T;
}
if (TmpRetVal != null && TmpRetVal is T && TmpRetVal.Name.String == Name.String)
return TmpRetVal as T;
foreach (var e in Params)
if (e.Name.String == Name.String && e is T)
return e as T;
return base.GetIdRec<T>(Name, Mode, SearchedInBasicTypes);
}
public string GetFunctionCode()
{
if (AsmCode == null)
CreateAsmCode();
return AsmCode;
}
public bool ChkRetMembers(CodeChkData Data, PString Command = null)
{
if (RetMembers == null) return true;
var RetValue = true;
foreach (var e in RetMembers)
if (!Data.IsAssigned(e))
{
if (Command == null) State.Messages.Add(MessageId.UnassignedVar, e.Name);
else State.Messages.Add(MessageId.UnassignedVar2, Command, e.Name.String);
RetValue = false;
}
return RetValue;
}
public override bool ProcessCode()
{
var Ret = base.ProcessCode();
if (!ProcessLabels()) Ret = false;
if (TmpRetVal != null && !CopyRetVal(Name))
Ret = false;
var RetLComm = CreateLabelCommand(RetLabel);
if (!AddCommand(null, RetLComm, false)) Ret = false;
if (Ret)
{
InitCodeChk();
var Data = new CodeChkData();
ChkCodeRec(Data, ref Ret);
if (!RetLComm.Unreachable)
{
if (NeedReturnVal(Type.RetType))
{
State.Messages.Add(MessageId.NotAllPathReturn, Name);
Ret = false;
}
if (!ChkRetMembers(Data))
Ret = false;
}
RetLComm.Unreachable = false;
if (!FinishCodeChk()) Ret = false;
}
return Ret;
}
}
}