1518 lines
50 KiB
C#
1518 lines
50 KiB
C#
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Text;
|
|
|
|
namespace langtest
|
|
{
|
|
public class ExpressionStream : Stream
|
|
{
|
|
|
|
Expression read,write,setpos,getpos,getlen,canread,canwrite,canseek,flush,destroy;
|
|
IApplicationState state;
|
|
|
|
public ExpressionStream(IApplicationState state,Expression read,Expression write,Expression setpos,Expression getpos,Expression getlen,Expression canread,Expression canwrite,Expression canseek,Expression flush,Expression destroy)
|
|
{
|
|
|
|
this.read =read;
|
|
this.write =canwrite;
|
|
this.setpos = setpos;
|
|
this.getpos = getpos;
|
|
this.getlen =getlen;
|
|
this.canread = canread;
|
|
this.canwrite = canwrite;
|
|
this.canseek = canseek;
|
|
this.destroy=destroy;
|
|
this.state = state;
|
|
this.flush = flush;
|
|
}
|
|
|
|
public override bool CanRead => canread.Evaluate(state) > 0;
|
|
|
|
public override bool CanSeek => canseek.Evaluate(state) > 0;
|
|
|
|
public override bool CanWrite => canwrite.Evaluate(state) > 0;
|
|
|
|
public override long Length => getlen.Evaluate(state);
|
|
|
|
private void _setLen(long len)
|
|
{
|
|
var newSc = state.NewScope();
|
|
newSc.SetVariable("stream_length_value",len);
|
|
setpos.Evaluate(newSc);
|
|
}
|
|
public override long Position { get => getlen.Evaluate(state); set => _setLen(value); }
|
|
|
|
public override void Flush()
|
|
{
|
|
flush.Execute(state);
|
|
}
|
|
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
{
|
|
var box=state.CreateBox(count);
|
|
var newSc = state.NewScope();
|
|
newSc.SetVariable("stream_count_value",count);
|
|
newSc.SetVariable("stream_buffer",box);
|
|
|
|
int read=(int)setpos.Evaluate(newSc);
|
|
//sorry for this inefficency but this is kind of a toy lang and my first one to finish
|
|
for(int i = 0;i<Math.Min(read,count);i++)
|
|
{
|
|
byte v=(byte)state.GetBoxValue(box,i);
|
|
buffer[i+offset] = v;
|
|
}
|
|
state.DestroyBox(box);
|
|
return Math.Min(read,count);
|
|
}
|
|
|
|
public override long Seek(long offset, SeekOrigin origin)
|
|
{
|
|
long pos = Position;
|
|
switch(origin)
|
|
{
|
|
case SeekOrigin.Begin:
|
|
pos=offset;
|
|
break;
|
|
case SeekOrigin.Current:
|
|
pos+=offset;
|
|
break;
|
|
case SeekOrigin.End:
|
|
pos = Length + offset;
|
|
break;
|
|
}
|
|
Position = pos;
|
|
return pos;
|
|
}
|
|
|
|
public override void SetLength(long value)
|
|
{
|
|
|
|
}
|
|
|
|
public override void Write(byte[] buffer, int offset, int count)
|
|
{
|
|
var box=state.CreateBox(count);
|
|
var newSc = state.NewScope();
|
|
newSc.SetVariable("stream_count_value",count);
|
|
newSc.SetVariable("stream_buffer",box);
|
|
|
|
|
|
//sorry for this inefficency but this is kind of a toy lang and my first one to finish
|
|
for(int i = 0;i<count;i++)
|
|
{
|
|
state.AddToBox(box,buffer[i+offset]);
|
|
}
|
|
setpos.Evaluate(newSc);
|
|
state.DestroyBox(box);
|
|
}
|
|
public override void Close()
|
|
{
|
|
destroy.Execute(state);
|
|
}
|
|
}
|
|
public class SubscopeApplicationState : IApplicationState
|
|
{
|
|
static long CID = 0;
|
|
private long _id = CID++;
|
|
public long Id {get{return _id;}}
|
|
IApplicationState state;
|
|
public SubscopeApplicationState(IApplicationState state)
|
|
{
|
|
this.state =state;
|
|
}
|
|
public long CreateBox(int boxLen=0)
|
|
{
|
|
return state.CreateBox(boxLen);
|
|
}
|
|
Dictionary<string,long> variables=new Dictionary<string, long>();
|
|
|
|
public long GetBoxValue(long bId, int index)
|
|
{
|
|
return state.GetBoxValue(bId,index);
|
|
}
|
|
|
|
public long GetVariable(string name)
|
|
{
|
|
if(!name.StartsWith("cur.") && state.HasVariable(name))
|
|
{
|
|
return state.GetVariable(name);
|
|
}else{
|
|
if(variables.ContainsKey(name))
|
|
{
|
|
return variables[name];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public bool HasVariable(string name)
|
|
{
|
|
return variables.ContainsKey(name) || (!name.StartsWith("cur.") && state.HasVariable(name));
|
|
}
|
|
|
|
public IApplicationState NewScope()
|
|
{
|
|
return new SubscopeApplicationState(this);
|
|
}
|
|
|
|
public void SetVariable(string name, long value)
|
|
{
|
|
if(!name.StartsWith("cur.") && state.HasVariable(name))
|
|
{
|
|
state.SetVariable(name,value);
|
|
}else{
|
|
if(variables.ContainsKey(name))
|
|
{
|
|
variables[name]=value;
|
|
}else{
|
|
variables.Add(name,value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ClearBox(long bId)
|
|
{
|
|
state.ClearBox(bId);
|
|
}
|
|
|
|
public void AddToBox(long bId, long value)
|
|
{
|
|
state.AddToBox(bId,value);
|
|
}
|
|
|
|
public void RemoveFromBox(long bId, long value)
|
|
{
|
|
state.RemoveFromBox(bId,value);
|
|
}
|
|
|
|
public void RemoveAtFromBox(long bId, int index)
|
|
{
|
|
state.RemoveAtFromBox(bId,index);
|
|
}
|
|
|
|
public void InsertToBox(long bId, int index, long value)
|
|
{
|
|
state.InsertToBox(bId,index,value);
|
|
}
|
|
|
|
public void SetBoxValue(long bId, int index, long value)
|
|
{
|
|
state.SetBoxValue(bId,index,value);
|
|
}
|
|
|
|
public long BoxLength(long boxId)
|
|
{
|
|
return state.BoxLength(boxId);
|
|
}
|
|
|
|
public long CreateBox(string text,bool permanent=false)
|
|
{
|
|
return state.CreateBox(text,permanent);
|
|
}
|
|
|
|
public string BoxToString(long boxId)
|
|
{
|
|
return state.BoxToString(boxId);
|
|
}
|
|
|
|
public long ExecuteFunction(string str, List<Expression> expressions)
|
|
{
|
|
return state.ExecuteFunction(str,expressions);
|
|
}
|
|
|
|
public bool HasFunction(string str)
|
|
{
|
|
return state.HasFunction(str);
|
|
}
|
|
|
|
public void AddFunction(string str, List<string> args, Expression exp)
|
|
{
|
|
state.AddFunction(str,args,exp);
|
|
}
|
|
|
|
public long CreateFile(long boxId)
|
|
{
|
|
return state.CreateFile(boxId);
|
|
}
|
|
|
|
public long OpenReadFile(long boxId)
|
|
{
|
|
return state.OpenReadFile(boxId);
|
|
}
|
|
|
|
public void CopyStream(long strmSrc, long strmDest)
|
|
{
|
|
state.CopyStream(strmSrc,strmDest);
|
|
}
|
|
|
|
public void CloseStream(long streamId)
|
|
{
|
|
state.CloseStream(streamId);
|
|
}
|
|
|
|
public void WriteToStream(long streamId, long boxId, long offset, long len)
|
|
{
|
|
state.WriteToStream(streamId,boxId,offset,len);
|
|
}
|
|
|
|
public long ReadFromStream(long streamId, long boxId, long offset, long len)
|
|
{
|
|
return state.ReadFromStream(streamId,boxId,offset,len);
|
|
}
|
|
|
|
public void SetStreamPosition(long streamId, long streamPos)
|
|
{
|
|
state.SetStreamPosition(streamId,streamPos);
|
|
}
|
|
|
|
public long GetStreamPosition(long streamId)
|
|
{
|
|
return state.GetStreamPosition(streamId);
|
|
}
|
|
|
|
public long GetStreamLength(long streamId)
|
|
{
|
|
return state.GetStreamLength(streamId);
|
|
}
|
|
|
|
public bool CanRead(long streamId)
|
|
{
|
|
return state.CanRead(streamId);
|
|
}
|
|
|
|
public bool CanWrite(long streamId)
|
|
{
|
|
return state.CanWrite(streamId);
|
|
}
|
|
|
|
public bool CanSeek(long streamId)
|
|
{
|
|
return state.CanSeek(streamId);
|
|
}
|
|
|
|
public long OpenWriteFile(long boxId)
|
|
{
|
|
return state.OpenWriteFile(boxId);
|
|
}
|
|
|
|
public long OpenReadWriteFile(long boxId)
|
|
{
|
|
return state.OpenReadWriteFile(boxId);
|
|
}
|
|
public long CreateStream(Stream strm)
|
|
{
|
|
return state.CreateStream(strm);
|
|
}
|
|
|
|
public long e2n(Expression e)
|
|
{
|
|
return state.e2n(e);
|
|
}
|
|
|
|
public Expression Calln(long e)
|
|
{
|
|
|
|
return state.Calln(e);
|
|
|
|
}
|
|
|
|
public void FlushStream(long stream)
|
|
{
|
|
state.FlushStream(stream);
|
|
}
|
|
|
|
public void DestroyBox(long id)
|
|
{
|
|
state.DestroyBox(id);
|
|
}
|
|
}
|
|
public class ApplicationState : IApplicationState
|
|
{
|
|
static long CID = 0;
|
|
private long _id = CID++;
|
|
public long Id {get{return _id;}}
|
|
public long NoStreams=0;
|
|
public long NoBoxes = 0;
|
|
public long NoExpressions=0;
|
|
public Dictionary<long,Expression> expressions = new Dictionary<long, Expression>();
|
|
|
|
|
|
public Dictionary<string,(List<string> param,Expression expression)> methods=new Dictionary<string, (List<string> param, Expression expression)>();
|
|
public Dictionary<long,Stream> streams=new Dictionary<long, Stream>();
|
|
public Dictionary<string,long> variables=new Dictionary<string, long>();
|
|
|
|
public Dictionary<long,(List<long>,bool perm )> boxes = new Dictionary<long, (List<long> data,bool perm)>();
|
|
|
|
public Expression Calln(long e)
|
|
{
|
|
if(expressions.ContainsKey(e))
|
|
{
|
|
return expressions[e];
|
|
}
|
|
return new ConstantNumber("0");
|
|
}
|
|
public long e2n(Expression e)
|
|
{
|
|
long eId = NoExpressions++;
|
|
expressions.Add(eId,e);
|
|
return eId;
|
|
}
|
|
|
|
public string BoxToString(long boxId)
|
|
{
|
|
StringBuilder bu= new StringBuilder();
|
|
if(!boxes.ContainsKey(boxId))
|
|
{
|
|
throw new Exception("Box does not exist");
|
|
}else{
|
|
var b = boxes[boxId].Item1;
|
|
foreach(var item in b)
|
|
{
|
|
char c = (char)(item % char.MaxValue);
|
|
bu.Append(c);
|
|
}
|
|
}
|
|
return bu.ToString();
|
|
}
|
|
public long CreateBox(int boxLen=0)
|
|
{
|
|
long i=NoBoxes++;
|
|
boxes.Add(i,(new List<long>(boxLen),false));
|
|
return i;
|
|
}
|
|
public void DestroyBox(long boxId)
|
|
{
|
|
if(!boxes.ContainsKey(boxId)) return;
|
|
if(!boxes[boxId].perm)
|
|
{
|
|
boxes[boxId].Item1.Clear();
|
|
boxes.Remove(boxId);
|
|
}
|
|
}
|
|
|
|
public long CreateStream(Stream strm)
|
|
{
|
|
long i = NoStreams++;
|
|
streams.Add(i,strm);
|
|
return i;
|
|
}
|
|
public long GetBoxValue(long bId, int index)
|
|
{
|
|
if(!boxes.ContainsKey(bId))
|
|
{
|
|
throw new Exception("Box does not exist");
|
|
}else{
|
|
var b = boxes[bId];
|
|
if(index > b.Item1.Count)
|
|
{
|
|
throw new IndexOutOfRangeException();
|
|
}else{
|
|
return b.Item1[index];
|
|
}
|
|
}
|
|
}
|
|
public void SetBoxValue(long bId,int index,long value)
|
|
{
|
|
if(value > int.MaxValue) throw new ArgumentOutOfRangeException("value > int.maxvalue");
|
|
|
|
if(!boxes.ContainsKey(bId))
|
|
{
|
|
throw new Exception("Box does not exist");
|
|
}else{
|
|
var b = boxes[bId];
|
|
if(b.perm) throw new ArgumentException("Cant manipulate read only value");
|
|
if(index > b.Item1.Count)
|
|
{
|
|
throw new IndexOutOfRangeException();
|
|
}else{
|
|
b.Item1[index] = value;
|
|
}
|
|
}
|
|
}
|
|
public bool HasVariable(string name)
|
|
{
|
|
return variables.ContainsKey(name);
|
|
}
|
|
|
|
public virtual long GetVariable(string name)
|
|
{
|
|
if(variables.ContainsKey(name))
|
|
{
|
|
//create_method(a,b,c,d,{})
|
|
return variables[name];
|
|
}else{
|
|
return 0;
|
|
}
|
|
|
|
}
|
|
|
|
public IApplicationState NewScope()
|
|
{
|
|
return new SubscopeApplicationState(this);
|
|
}
|
|
|
|
public virtual void SetVariable(string name, long value)
|
|
{
|
|
if(variables.ContainsKey(name))
|
|
{
|
|
variables[name]=value;
|
|
}else{
|
|
variables.Add(name,value);
|
|
}
|
|
}
|
|
|
|
public void ClearBox(long bId)
|
|
{
|
|
|
|
if(!boxes.ContainsKey(bId))
|
|
{
|
|
throw new Exception("Box does not exist");
|
|
}else{
|
|
var b = boxes[bId];
|
|
if(b.perm) throw new ArgumentException("Cant manipulate read only value");
|
|
|
|
b.Item1.Clear();
|
|
}
|
|
}
|
|
|
|
public void AddToBox(long bId, long value)
|
|
{
|
|
|
|
if(!boxes.ContainsKey(bId))
|
|
{
|
|
throw new Exception("Box does not exist");
|
|
}else{
|
|
var b = boxes[bId];
|
|
if(b.perm) throw new ArgumentException("Cant manipulate read only value");
|
|
|
|
b.Item1.Add(value);
|
|
|
|
}
|
|
}
|
|
|
|
public void RemoveFromBox(long bId, long value)
|
|
{
|
|
|
|
if(!boxes.ContainsKey(bId))
|
|
{
|
|
throw new Exception("Box does not exist");
|
|
}else{
|
|
var b = boxes[bId];
|
|
if(b.perm) throw new ArgumentException("Cant manipulate read only value");
|
|
|
|
b.Item1.Remove(value);
|
|
|
|
}
|
|
}
|
|
|
|
public void RemoveAtFromBox(long bId, int index)
|
|
{
|
|
|
|
if(!boxes.ContainsKey(bId))
|
|
{
|
|
throw new Exception("Box does not exist");
|
|
}else{
|
|
var b = boxes[bId];
|
|
if(b.perm) throw new ArgumentException("Cant manipulate read only value");
|
|
|
|
b.Item1.RemoveAt(index);
|
|
|
|
}
|
|
}
|
|
|
|
public void InsertToBox(long bId, int index, long value)
|
|
{
|
|
|
|
if(!boxes.ContainsKey(bId))
|
|
{
|
|
throw new Exception("Box does not exist");
|
|
}else{
|
|
var b = boxes[bId];
|
|
if(b.perm) throw new ArgumentException("Cant manipulate read only value");
|
|
|
|
b.Item1.Insert(index,value);
|
|
|
|
}
|
|
}
|
|
|
|
public long BoxLength(long boxId)
|
|
{
|
|
|
|
if(!boxes.ContainsKey(boxId))
|
|
{
|
|
throw new Exception("Box does not exist");
|
|
}else{
|
|
var b = boxes[boxId];
|
|
|
|
return b.Item1.Count;
|
|
|
|
}
|
|
}
|
|
public long ExecuteFunction(string str,List<Expression> expressions)
|
|
{
|
|
if(!HasFunction(str)) return 0;
|
|
var func=methods[str];
|
|
var res=NewScope();
|
|
for(int i = 0;i<Math.Min(expressions.Count,func.param.Count);i++)
|
|
{
|
|
res.SetVariable(func.param[i],expressions[i].Evaluate(res));
|
|
}
|
|
return func.expression.Evaluate(res);
|
|
}
|
|
public long CreateBox(string text,bool permanent=false)
|
|
{
|
|
long i=NoBoxes++;
|
|
boxes.Add(i,(new List<long>(text.Select<char,long>((e)=>{return e;})),permanent));
|
|
return i;
|
|
}
|
|
|
|
public bool HasFunction(string str)
|
|
{
|
|
return methods.ContainsKey(str);
|
|
}
|
|
|
|
public void AddFunction(string str, List<string> args, Expression exp)
|
|
{
|
|
if(!HasFunction(str))
|
|
{
|
|
methods.Add(str,(args,exp));
|
|
}
|
|
}
|
|
|
|
public long CreateFile(long boxId)
|
|
{
|
|
string filename=BoxToString(boxId);
|
|
|
|
return CreateStream(File.Create(filename));
|
|
}
|
|
|
|
public long OpenReadFile(long boxId)
|
|
{
|
|
string filename=BoxToString(boxId);
|
|
|
|
return CreateStream(File.OpenRead(filename));
|
|
}
|
|
private Stream GetStream(long strmId)
|
|
{
|
|
if(!streams.ContainsKey(strmId)) throw new Exception("No stream with specified id");
|
|
return streams[strmId];
|
|
}
|
|
|
|
public void CopyStream(long strmSrc, long strmDest)
|
|
{
|
|
GetStream(strmSrc).CopyTo(GetStream(strmDest));
|
|
}
|
|
|
|
public void CloseStream(long streamId)
|
|
{
|
|
if(!streams.ContainsKey(streamId)) return;
|
|
GetStream(streamId).Dispose();
|
|
streams.Remove(streamId);
|
|
}
|
|
|
|
public void WriteToStream(long streamId, long boxId, long offset, long len)
|
|
{
|
|
List<long> box = boxes[boxId].Item1;
|
|
byte[] data=box.Skip((int)offset).Take((int)len).Select<long,byte>((e)=>{
|
|
return (byte)(e % 256);
|
|
}).ToArray();
|
|
|
|
GetStream(streamId).Write(data,0,data.Length);
|
|
}
|
|
|
|
public long ReadFromStream(long streamId, long boxId, long offset, long len)
|
|
{
|
|
var bo = boxes[boxId];
|
|
if(bo.perm) return 0;
|
|
List<long> box = boxes[boxId].Item1;
|
|
len = Math.Min(len,box.Count - offset);
|
|
byte[] data=new byte[len];
|
|
int read=GetStream(streamId).Read(data,0,(int)len);
|
|
for(int i =0;i<read;i++)
|
|
{
|
|
box[i+(int)offset] = data[i];
|
|
}
|
|
return read;
|
|
}
|
|
|
|
public void SetStreamPosition(long streamId, long streamPos)
|
|
{
|
|
GetStream(streamId).Position = streamPos;
|
|
}
|
|
|
|
public long GetStreamPosition(long streamId)
|
|
{
|
|
return GetStream(streamId).Position;
|
|
}
|
|
|
|
public long GetStreamLength(long streamId)
|
|
{
|
|
return GetStream(streamId).Length;
|
|
}
|
|
|
|
public bool CanRead(long streamId)
|
|
{
|
|
return GetStream(streamId).CanRead;
|
|
}
|
|
|
|
public bool CanWrite(long streamId)
|
|
{
|
|
return GetStream(streamId).CanWrite;
|
|
}
|
|
|
|
public bool CanSeek(long streamId)
|
|
{
|
|
return GetStream(streamId).CanSeek;
|
|
}
|
|
|
|
public long OpenWriteFile(long boxId)
|
|
{
|
|
string filename=BoxToString(boxId);
|
|
|
|
return CreateStream(File.OpenWrite(filename));
|
|
}
|
|
|
|
public long OpenReadWriteFile(long boxId)
|
|
{
|
|
string filename=BoxToString(boxId);
|
|
|
|
return CreateStream(File.Open(filename,FileMode.OpenOrCreate,FileAccess.ReadWrite));
|
|
}
|
|
|
|
public void FlushStream(long stream)
|
|
{
|
|
if(!streams.ContainsKey(stream)) return;
|
|
GetStream(stream).Flush();
|
|
}
|
|
}
|
|
public interface IApplicationState
|
|
{
|
|
void FlushStream(long stream);
|
|
void DestroyBox(long id);
|
|
public long e2n(Expression e);
|
|
public Expression Calln(long e);
|
|
long CreateStream(Stream strm);
|
|
long CreateFile(long boxId);
|
|
long OpenReadFile(long boxId);
|
|
long OpenWriteFile(long boxId);
|
|
|
|
long OpenReadWriteFile(long boxId);
|
|
|
|
void CopyStream(long strmSrc,long strmDest);
|
|
|
|
void CloseStream(long streamId);
|
|
|
|
void WriteToStream(long streamId,long boxId,long offset,long len);
|
|
|
|
long ReadFromStream(long streamId,long boxId,long offset,long len);
|
|
|
|
void SetStreamPosition(long streamId,long streamPos);
|
|
|
|
long GetStreamPosition(long streamId);
|
|
|
|
long GetStreamLength(long streamId);
|
|
|
|
bool CanRead(long streamId);
|
|
bool CanWrite(long streamId);
|
|
bool CanSeek(long streamId);
|
|
|
|
long ExecuteFunction(string str,List<Expression> expressions);
|
|
bool HasFunction(string str);
|
|
void AddFunction(string str,List<string> args,Expression exp);
|
|
string BoxToString(long boxId);
|
|
void ClearBox(long bId);
|
|
void AddToBox(long bId,long value);
|
|
void RemoveFromBox(long bId,long value);
|
|
void RemoveAtFromBox(long bId,int index);
|
|
void InsertToBox(long bId,int index,long value);
|
|
|
|
void SetBoxValue(long bId,int index,long value);
|
|
void SetVariable(string name,long value);
|
|
long GetVariable(string name);
|
|
|
|
long BoxLength(long boxId);
|
|
|
|
long CreateBox(int len=0);
|
|
long CreateBox(string text,bool permanent=false);
|
|
long GetBoxValue(long bId, int index);
|
|
bool HasVariable(string name);
|
|
|
|
IApplicationState NewScope();
|
|
}
|
|
public static class Ast
|
|
{
|
|
public static void Parse(ListNode node,List<LexToken> tokens)
|
|
{
|
|
int i = 0;
|
|
ParseNode(node,tokens,ref i,true);
|
|
}
|
|
public static ListNode Parse(List<LexToken> tokens)
|
|
{
|
|
int i = 0;
|
|
ListNode node=new ListNode();
|
|
ParseNode(node,tokens,ref i,true);
|
|
return node;
|
|
}
|
|
public static void ParseNode(ListNode node,List<LexToken> tokens,ref int i,bool root=false)
|
|
{
|
|
node.Root=root;
|
|
|
|
//i = 0
|
|
//0
|
|
//func()
|
|
|
|
while(i<tokens.Count && tokens[i].Type != LexTokenType.RBRACE)
|
|
{
|
|
if(tokens[i].Type == LexTokenType.SEMI) i++;
|
|
|
|
if(i+2 < tokens.Count && tokens[i+1].Type == LexTokenType.EQUALS)
|
|
{
|
|
string varname = tokens[i].Text;
|
|
|
|
i+=2;
|
|
node.Nodes.Add(new SetVariableNode(ParseExpression(tokens,ref i),varname));
|
|
if(!root && i<tokens.Count && tokens[i].Type == LexTokenType.RBRACE) break;
|
|
|
|
i++;
|
|
}
|
|
else if(i+1 < tokens.Count && tokens[i+1].Type == LexTokenType.LPAREN)
|
|
{
|
|
node.Nodes.Add(ParseExpression(tokens,ref i));
|
|
if(!root && i<tokens.Count && tokens[i].Type == LexTokenType.RBRACE) break;
|
|
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
|
|
node.Nodes.Add(ParseExpression(tokens,ref i));
|
|
|
|
|
|
if(!root && i<tokens.Count && tokens[i].Type == LexTokenType.RBRACE) break;
|
|
|
|
i++;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
private static Expression ParseExpression(List<LexToken> tokens,ref int i)
|
|
{
|
|
Expression res= ParseTerm(tokens,ref i);
|
|
while(i < tokens.Count && (tokens[i].Type == LexTokenType.PLUS || tokens[i].Type == LexTokenType.MINUS))
|
|
{
|
|
if(i < tokens.Count && tokens[i].Type == LexTokenType.PLUS)
|
|
{
|
|
i++;
|
|
res = new AddNode(res,ParseTerm(tokens,ref i));
|
|
}
|
|
if(i < tokens.Count && tokens[i].Type == LexTokenType.MINUS)
|
|
{
|
|
i++;
|
|
res = new MinusNode(res,ParseTerm(tokens,ref i));
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
private static Expression ParseTerm(List<LexToken> tokens,ref int i)
|
|
{
|
|
Expression res= ParseFactor(tokens,ref i);
|
|
while(i < tokens.Count && (tokens[i].Type == LexTokenType.MULTIPLY || tokens[i].Type == LexTokenType.DIVIDE || tokens[i].Type == LexTokenType.MOD))
|
|
{
|
|
if(i < tokens.Count && tokens[i].Type == LexTokenType.MULTIPLY)
|
|
{
|
|
i++;
|
|
res = new MultiplyNode(res,ParseFactor(tokens,ref i));
|
|
}
|
|
if(i < tokens.Count && tokens[i].Type == LexTokenType.DIVIDE)
|
|
{
|
|
i++;
|
|
res = new DivideNode(res,ParseFactor(tokens,ref i));
|
|
}
|
|
if(i < tokens.Count && tokens[i].Type == LexTokenType.MOD)
|
|
{
|
|
i++;
|
|
res = new ModulusNode(res,ParseFactor(tokens,ref i));
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
private static Expression ParseFactor(List<LexToken> tokens,ref int i)
|
|
{
|
|
if(i>=tokens.Count) throw new ArgumentOutOfRangeException("i>=tokens.Count");
|
|
var token = tokens[i];
|
|
if(token.Type == LexTokenType.LPAREN)
|
|
{
|
|
i++;
|
|
var res = ParseExpression(tokens,ref i);
|
|
if(i>=tokens.Count) throw new ArgumentOutOfRangeException("i>=tokens.Count");
|
|
if(tokens[i].Type != LexTokenType.RPAREN) throw new ArgumentException("tokens[i].Type != RPAREN");
|
|
i++;
|
|
return res;
|
|
}
|
|
if(token.Type == LexTokenType.LBRACE)
|
|
{
|
|
i++;
|
|
ListNode res=new ListNode();
|
|
ParseNode(res,tokens,ref i,false);
|
|
if(i>=tokens.Count) throw new ArgumentOutOfRangeException("i>=tokens.Count");
|
|
if(tokens[i].Type != LexTokenType.RBRACE) throw new ArgumentException("tokens[i].Type != RBRACE");
|
|
i++;
|
|
return res;
|
|
}
|
|
if(token.Type == LexTokenType.IDENTIFER)
|
|
{
|
|
i++;
|
|
if(i<tokens.Count && tokens[i].Type == LexTokenType.LPAREN)
|
|
{
|
|
List<Expression> funcArgs = new List<Expression>();
|
|
//check whether its args
|
|
i++;
|
|
while(i<tokens.Count && tokens[i].Type != LexTokenType.RPAREN)
|
|
{
|
|
if(tokens[i].Type == LexTokenType.COMMA) i++;
|
|
funcArgs.Add(ParseExpression(tokens,ref i));
|
|
|
|
}
|
|
i++;
|
|
return new FunctionCallNode(token.Text,funcArgs);
|
|
}else{
|
|
return new VariableGetValueNode(token.Text);
|
|
}
|
|
}
|
|
if(token.Type == LexTokenType.STRING)
|
|
{
|
|
i++;
|
|
return new StringNode(token.Text);
|
|
}
|
|
|
|
if(token.Type == LexTokenType.NUMBER)
|
|
{
|
|
i++;
|
|
return new ConstantNumber(token.Text);
|
|
}
|
|
throw new Exception("Not found factor");
|
|
}
|
|
}
|
|
public class StringNode : Expression
|
|
{
|
|
long boxId=-1;
|
|
string text;
|
|
public StringNode(string text)
|
|
{
|
|
this.text = text;
|
|
}
|
|
public override long Evaluate(IApplicationState state)
|
|
{
|
|
if(boxId > -1)
|
|
return boxId;
|
|
|
|
boxId = state.CreateBox(text,true);
|
|
return boxId;
|
|
}
|
|
}
|
|
public class ConstantNumber : Expression
|
|
{
|
|
long num;
|
|
public ConstantNumber(string num)
|
|
{
|
|
if(!long.TryParse(num,out this.num))
|
|
{
|
|
this.num=0;
|
|
}
|
|
}
|
|
public override long Evaluate(IApplicationState state)
|
|
{
|
|
return num;
|
|
}
|
|
}
|
|
public class SetVariableNode : Node
|
|
{
|
|
Expression e;
|
|
string vname;
|
|
public SetVariableNode(Expression expression,string varName)
|
|
{
|
|
this.e=expression;
|
|
this.vname = varName;
|
|
}
|
|
public override void Execute(IApplicationState state)
|
|
{
|
|
var v =e.Evaluate(state);
|
|
state.SetVariable(vname,v);
|
|
|
|
}
|
|
}
|
|
|
|
public class FunctionCallNode : Expression
|
|
{
|
|
string name;
|
|
List<Expression> expressions;
|
|
public FunctionCallNode(string name,List<Expression> expressions)
|
|
{
|
|
this.name=name;
|
|
this.expressions=expressions;
|
|
}
|
|
public override long Evaluate(IApplicationState state)
|
|
{
|
|
if(name == "gt")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) > expressions[1].Evaluate(state) ? 1 : 0;
|
|
}
|
|
else
|
|
if(name == "gte")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) >= expressions[1].Evaluate(state) ? 1 : 0;
|
|
|
|
}else if(name == "lt")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) < expressions[1].Evaluate(state) ? 1 : 0;
|
|
|
|
}else if(name == "lte")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) <= expressions[1].Evaluate(state) ? 1 : 0;
|
|
|
|
}
|
|
else if(name == "eq")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) == expressions[1].Evaluate(state) ? 1 : 0;
|
|
|
|
}
|
|
else
|
|
if(name == "not")
|
|
{
|
|
if(expressions.Count < 1) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) != 0 ? 0 : 1;
|
|
|
|
}else if(name == "xor")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) ^ expressions[1].Evaluate(state);
|
|
|
|
}else if(name == "bor")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) | expressions[1].Evaluate(state);
|
|
|
|
}else if(name == "cor")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) != 0 || expressions[1].Evaluate(state) != 0 ? 1 : 0;
|
|
|
|
|
|
}else if(name == "band")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) & expressions[1].Evaluate(state);
|
|
|
|
}else if(name == "cand")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) != 0 && expressions[1].Evaluate(state) != 0 ? 1 : 0;
|
|
|
|
}else if(name == "lshift")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) << (int) expressions[1].Evaluate(state);
|
|
}else if(name == "rshift")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("need two param");
|
|
return expressions[0].Evaluate(state) >> (int) expressions[1].Evaluate(state);
|
|
|
|
}
|
|
if(name == "printint")
|
|
{
|
|
foreach(var exp in expressions)
|
|
{
|
|
Console.WriteLine(exp.Evaluate(state));
|
|
}
|
|
}else
|
|
if(name == "printchars")
|
|
{
|
|
foreach(var exp in expressions)
|
|
{
|
|
char res = (char)(exp.Evaluate(state) % char.MaxValue);
|
|
Console.Write(res);
|
|
}
|
|
}
|
|
else if(name == "tcp_client")
|
|
{
|
|
Expression listenIp = expressions[0];
|
|
Expression listenPort = expressions[1];
|
|
TcpClient clt=new TcpClient(state.BoxToString(listenIp.Evaluate(state)),(int)listenPort.Evaluate(state));
|
|
var strm=clt.GetStream();
|
|
return state.CreateStream(strm);
|
|
}
|
|
else
|
|
if(name == "tcp_server")
|
|
{
|
|
Expression listenIp = expressions[0];
|
|
Expression listenPort = expressions[1];
|
|
VariableGetValueNode? stream_name = expressions[2] as VariableGetValueNode;
|
|
VariableGetValueNode? ip_name = expressions[3] as VariableGetValueNode;
|
|
|
|
Expression exp = expressions[4];
|
|
|
|
if(stream_name == null) throw new Exception("You must use identifier at positional arg #3 (starting from 1)");
|
|
if(ip_name == null) throw new Exception("You must use identifier at positional arg #4 (starting from 1)");
|
|
string name = stream_name.Name;
|
|
string ipname = ip_name.Name;
|
|
//tcpserver("0.0.0.0",4202,strm,ip,{})
|
|
TcpListener listener = new TcpListener(new IPEndPoint(IPAddress.Parse(state.BoxToString(listenIp.Evaluate(state))),(int)listenPort.Evaluate(state)));
|
|
listener.Start();
|
|
while(true)
|
|
{
|
|
var clt= listener.AcceptTcpClient();
|
|
NetworkStream stream = clt.GetStream();
|
|
var s=state.NewScope();
|
|
long str =s.CreateStream(stream);
|
|
s.SetVariable(name,str);
|
|
string? ip=clt.Client?.RemoteEndPoint?.ToString();
|
|
if(string.IsNullOrWhiteSpace(ip)) ip="";
|
|
|
|
s.SetVariable(ipname,s.CreateBox(ip));
|
|
exp.Execute(s);
|
|
s.CloseStream(str);
|
|
}
|
|
}else
|
|
|
|
if(name == "clear")
|
|
{
|
|
Console.Clear();
|
|
}else
|
|
if(name == "exit")
|
|
{
|
|
if(expressions.Count == 0){
|
|
Environment.Exit(0);
|
|
}else{
|
|
int i = (int)(expressions[0].Evaluate(state) % int.MaxValue);
|
|
Environment.Exit(i);
|
|
}
|
|
}else
|
|
if(name == "for")
|
|
{
|
|
if(expressions.Count < 4) throw new Exception("Need variable, max, incrementer, scope");
|
|
//for(i,30,i+1,)
|
|
VariableGetValueNode? vgvn = expressions[0] as VariableGetValueNode;
|
|
|
|
if(vgvn == null) throw new Exception("Not get value node");
|
|
string variableName = vgvn.Name;
|
|
long max= expressions[1].Evaluate(state);
|
|
Expression increment = expressions[2];
|
|
Expression runInFor = expressions[3];
|
|
|
|
for(;state.GetVariable(variableName) < max; state.SetVariable(variableName,increment.Evaluate(state)))
|
|
{
|
|
runInFor.Execute(state);
|
|
}
|
|
|
|
}else
|
|
if(name == "if")
|
|
{
|
|
//if(condition,truth,false)
|
|
if(expressions.Count < 3) throw new Exception("Need condition, true, false, hint use 0 to not use true or false");
|
|
|
|
Expression condition = expressions[0];
|
|
Expression truth = expressions[1];
|
|
Expression falsey = expressions[2];
|
|
|
|
if(condition.Evaluate(state) != 0)
|
|
{
|
|
truth.Execute(state);
|
|
}else{
|
|
falsey.Execute(state);
|
|
}
|
|
|
|
}else if(name == "e2n")
|
|
{
|
|
if(expressions.Count > 0)
|
|
{
|
|
return state.e2n(expressions[0]);
|
|
}
|
|
throw new Exception("I need an expression");
|
|
}else if(name == "calln")
|
|
{
|
|
if(expressions.Count > 0)
|
|
{
|
|
return state.Calln(expressions[0].Evaluate(state)).Evaluate(state);
|
|
}
|
|
throw new Exception("I need a number");
|
|
}
|
|
else
|
|
if(name == "box_create")
|
|
{
|
|
if(expressions.Count > 0)
|
|
{
|
|
long esize = expressions[0].Evaluate(state);
|
|
if(esize > int.MaxValue) throw new ArgumentOutOfRangeException("size > int.maxvalue");
|
|
int size = (int)esize;
|
|
return state.CreateBox(size);
|
|
}
|
|
return state.CreateBox();
|
|
}else
|
|
if(name == "box_getvalue")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("Need box id and index");
|
|
long bId = expressions[0].Evaluate(state);
|
|
long eindex = expressions[1].Evaluate(state);
|
|
if(eindex > int.MaxValue) throw new ArgumentOutOfRangeException("index > int.maxvalue");
|
|
int index = (int)eindex;
|
|
|
|
return state.GetBoxValue(bId,index);
|
|
|
|
}else
|
|
if(name == "box_setvalue")
|
|
{
|
|
if(expressions.Count < 3) throw new Exception("Need box id and index and value");
|
|
long bId = expressions[0].Evaluate(state);
|
|
long eindex = expressions[1].Evaluate(state);
|
|
if(eindex > int.MaxValue) throw new ArgumentOutOfRangeException("index > max.value");
|
|
int index = (int)eindex;
|
|
long value = expressions[2].Evaluate(state);
|
|
|
|
state.SetBoxValue(bId,index,value);
|
|
|
|
|
|
}
|
|
else
|
|
if(name == "box_print")
|
|
{
|
|
if(expressions.Count < 1)throw new Exception("Need box id");
|
|
long bId = expressions[0].Evaluate(state);
|
|
Console.Write(state.BoxToString(bId));
|
|
}else
|
|
if(name == "box_println")
|
|
{
|
|
if(expressions.Count < 1)throw new Exception("Need box id");
|
|
long bId = expressions[0].Evaluate(state);
|
|
Console.WriteLine(state.BoxToString(bId));
|
|
}
|
|
else
|
|
if(name == "box_len")
|
|
{
|
|
if(expressions.Count < 1)throw new Exception("Need box id");
|
|
long bId = expressions[0].Evaluate(state);
|
|
return state.BoxLength(bId);
|
|
}else
|
|
if(name == "box_add")
|
|
{
|
|
if(expressions.Count < 2)throw new Exception("Need box id and value");
|
|
long bId = expressions[0].Evaluate(state);
|
|
long value = expressions[1].Evaluate(state);
|
|
state.AddToBox(bId,value);
|
|
}else
|
|
if(name == "box_remove")
|
|
{
|
|
if(expressions.Count < 2)throw new Exception("Need box id and value");
|
|
long bId = expressions[0].Evaluate(state);
|
|
long value = expressions[1].Evaluate(state);
|
|
state.RemoveFromBox(bId,value);
|
|
}else
|
|
if(name == "box_clear")
|
|
{
|
|
if(expressions.Count < 1)throw new Exception("Need box id");
|
|
long bId = expressions[0].Evaluate(state);
|
|
state.ClearBox(bId);
|
|
}
|
|
else if(name == "file_create")
|
|
{
|
|
if(expressions.Count < 1)throw new Exception("Need box id");
|
|
long bId = expressions[0].Evaluate(state);
|
|
return state.CreateFile(bId);
|
|
|
|
}else if(name == "file_open_read")
|
|
{
|
|
if(expressions.Count < 1)throw new Exception("Need box id");
|
|
long bId = expressions[0].Evaluate(state);
|
|
return state.OpenReadFile(bId);
|
|
}else if(name == "file_open_write")
|
|
{
|
|
if(expressions.Count < 1)throw new Exception("Need box id");
|
|
long bId = expressions[0].Evaluate(state);
|
|
return state.OpenWriteFile(bId);
|
|
}
|
|
else if(name == "file_open_readwrite")
|
|
{
|
|
if(expressions.Count < 1)throw new Exception("Need box id");
|
|
long bId = expressions[0].Evaluate(state);
|
|
return state.OpenReadWriteFile(bId);
|
|
}
|
|
else if(name == "stream_copy")
|
|
{
|
|
if(expressions.Count < 2)throw new Exception("Need src and dest streamid");
|
|
long sId1= expressions[0].Evaluate(state);
|
|
long sId2 = expressions[1].Evaluate(state);
|
|
|
|
state.CopyStream(sId1,sId2);
|
|
}
|
|
else if(name == "stream_read")
|
|
{
|
|
if(expressions.Count < 4)throw new Exception("Need stream id and box id and offset and length");
|
|
long sId = expressions[0].Evaluate(state);
|
|
long bId = expressions[1].Evaluate(state);
|
|
long offset = expressions[2].Evaluate(state);
|
|
long len = expressions[3].Evaluate(state);
|
|
return state.ReadFromStream(sId,bId,offset,len);
|
|
}
|
|
else if(name == "stream_write")
|
|
{
|
|
if(expressions.Count < 4)throw new Exception("Need stream id and box id and offset and length");
|
|
long sId = expressions[0].Evaluate(state);
|
|
long bId = expressions[1].Evaluate(state);
|
|
long offset = expressions[2].Evaluate(state);
|
|
long len = expressions[3].Evaluate(state);
|
|
state.WriteToStream(sId,bId,offset,len);
|
|
}else if(name == "stream_close")
|
|
{
|
|
if(expressions.Count < 1)throw new Exception("Need stream id");
|
|
long sId = expressions[0].Evaluate(state);
|
|
state.CloseStream(sId);
|
|
}
|
|
else
|
|
if(name == "create_function")
|
|
{
|
|
if(expressions.Count < 2) throw new Exception("Need at least a name and body");
|
|
//create_function(function_name,arg0,arg1,arg2,scope)
|
|
VariableGetValueNode? vgvn = expressions[0] as VariableGetValueNode;
|
|
List<string> args=new List<string>();
|
|
if(vgvn == null) throw new Exception("Name must be identifier");
|
|
for(int i = 1;i<expressions.Count -1;i++)
|
|
{
|
|
VariableGetValueNode? vgvnArg = expressions[i] as VariableGetValueNode;
|
|
if(vgvnArg == null) throw new Exception("Arg must be identifier");
|
|
args.Add(vgvnArg.Name);
|
|
}
|
|
state.AddFunction(vgvn.Name,args,expressions[expressions.Count-1]);
|
|
}else if(name == "box_insert")
|
|
{
|
|
if(expressions.Count < 2)throw new Exception("Need box id and index and value");
|
|
long bId = expressions[0].Evaluate(state);
|
|
long eindex = expressions[1].Evaluate(state);
|
|
if(eindex > int.MaxValue) throw new ArgumentOutOfRangeException("index > int.maxvalue");
|
|
int index = (int)eindex;
|
|
long value = expressions[2].Evaluate(state);
|
|
state.InsertToBox(bId,index,value);
|
|
}else if(name == "box_removeat")
|
|
{
|
|
if(expressions.Count < 2)throw new Exception("Need box id and index");
|
|
long bId = expressions[0].Evaluate(state);
|
|
long eindex = expressions[1].Evaluate(state);
|
|
if(eindex > int.MaxValue) throw new ArgumentOutOfRangeException("index > int.maxvalue");
|
|
int index = (int)eindex;
|
|
|
|
state.RemoveAtFromBox(bId,index);
|
|
}
|
|
else if(name == "stream_create")
|
|
{
|
|
if(expressions.Count < 10)throw new Exception("Need box stream read, write,setpos,getpos,getlen,canread,canwrite,canseek,flush,destroy");
|
|
var cstrm=new ExpressionStream(state,expressions[0],expressions[1],expressions[2],expressions[3],expressions[4],expressions[5],expressions[6],expressions[7],expressions[8],expressions[9]);
|
|
return state.CreateStream(cstrm);
|
|
}
|
|
else if(name == "stream_flush")
|
|
{
|
|
if(expressions.Count < 1) throw new Exception("Need stream id");
|
|
state.FlushStream(expressions[0].Evaluate(state));
|
|
}
|
|
else
|
|
if(name == "box_readline")
|
|
{
|
|
string? text = Console.ReadLine();
|
|
if(string.IsNullOrWhiteSpace(text)) text="";
|
|
state.CreateBox(text);
|
|
|
|
}else
|
|
if(name == "readchar")
|
|
{
|
|
return Console.Read();
|
|
}else
|
|
if(name == "mean")
|
|
{
|
|
long v=0;
|
|
foreach(var exp in expressions)
|
|
{
|
|
v += exp.Evaluate(state);
|
|
}
|
|
v /= expressions.Count;
|
|
return v;
|
|
}else if(state.HasFunction(name))
|
|
{
|
|
return state.ExecuteFunction(name,expressions);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
public class VariableGetValueNode : Expression
|
|
{
|
|
public string Name {get{return var;}}
|
|
string var;
|
|
public VariableGetValueNode(string var)
|
|
{
|
|
this.var=var;
|
|
}
|
|
|
|
public override long Evaluate(IApplicationState state)
|
|
{
|
|
return state.GetVariable(var);
|
|
}
|
|
}
|
|
public class AddNode : Expression
|
|
{
|
|
public AddNode(Expression left,Expression right)
|
|
{
|
|
Left=left;
|
|
Right = right;
|
|
}
|
|
public Expression? Left;
|
|
public Expression? Right;
|
|
|
|
public override long Evaluate(IApplicationState state)
|
|
{
|
|
if(Left != null && Right != null)
|
|
{
|
|
return Left.Evaluate(state) + Right.Evaluate(state);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
public class MinusNode : Expression
|
|
{
|
|
public MinusNode(Expression left,Expression right)
|
|
{
|
|
Left=left;
|
|
Right = right;
|
|
}
|
|
public Expression? Left;
|
|
public Expression? Right;
|
|
|
|
public override long Evaluate(IApplicationState state)
|
|
{
|
|
if(Left != null && Right != null)
|
|
{
|
|
return Left.Evaluate(state) - Right.Evaluate(state);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
public class MultiplyNode : Expression
|
|
{
|
|
public MultiplyNode(Expression left,Expression right)
|
|
{
|
|
Left=left;
|
|
Right = right;
|
|
}
|
|
public Expression? Left;
|
|
public Expression? Right;
|
|
|
|
public override long Evaluate(IApplicationState state)
|
|
{
|
|
if(Left != null && Right != null)
|
|
{
|
|
return Left.Evaluate(state) * Right.Evaluate(state);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
public class DivideNode : Expression
|
|
{
|
|
public DivideNode(Expression left,Expression right)
|
|
{
|
|
Left=left;
|
|
Right = right;
|
|
}
|
|
public Expression? Left;
|
|
public Expression? Right;
|
|
|
|
public override long Evaluate(IApplicationState state)
|
|
{
|
|
if(Left != null && Right != null)
|
|
{
|
|
return Left.Evaluate(state) / Right.Evaluate(state);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
public class ModulusNode : Expression
|
|
{
|
|
public ModulusNode(Expression left,Expression right)
|
|
{
|
|
Left=left;
|
|
Right = right;
|
|
}
|
|
public Expression? Left;
|
|
public Expression? Right;
|
|
|
|
public override long Evaluate(IApplicationState state)
|
|
{
|
|
if(Left != null && Right != null)
|
|
{
|
|
return Left.Evaluate(state) % Right.Evaluate(state);
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
public abstract class Expression : Node
|
|
{
|
|
public abstract long Evaluate(IApplicationState state);
|
|
public override void Execute(IApplicationState state)
|
|
{
|
|
Evaluate(state);
|
|
}
|
|
}
|
|
public abstract class Node
|
|
{
|
|
public override string ToString()
|
|
{
|
|
StringBuilder b=new StringBuilder();
|
|
var t=GetType();
|
|
foreach(var p in t.GetProperties())
|
|
{
|
|
b.AppendLine($"{p.Name}:\n{TabOver(p.GetValue(this))}");
|
|
}
|
|
|
|
return b.ToString();
|
|
}
|
|
private string TabOver(object? p)
|
|
{
|
|
StringBuilder b=new StringBuilder();
|
|
string? j = p?.ToString();
|
|
if(string.IsNullOrWhiteSpace(j)) j ="";
|
|
foreach(var ln in j.Split(Environment.NewLine))
|
|
{
|
|
b.AppendLine($"\t{ln}");
|
|
}
|
|
return b.ToString();
|
|
}
|
|
|
|
|
|
public abstract void Execute(IApplicationState state);
|
|
}
|
|
public class ListNode : Expression
|
|
{
|
|
public bool Root {get;set;}
|
|
public List<Node> Nodes = new List<Node>();
|
|
public override long Evaluate(IApplicationState state)
|
|
{
|
|
var s = Root ? state : state.NewScope();
|
|
|
|
long res=0;
|
|
foreach(var node in Nodes)
|
|
{
|
|
Expression? e = node as Expression;
|
|
if(e != null)
|
|
{
|
|
|
|
res=e.Evaluate(s);
|
|
}
|
|
else{
|
|
node.Execute(s);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
}
|
|
} |