commit 024342d4da23384b46ce41cdfb013c5737daf59c Author: Mike Nolan Date: Sat Nov 26 20:16:48 2022 -0600 Initial Commit diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..de3fe62 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,26 @@ +{ + "version": "0.2.0", + "configurations": [ + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/net6.0/langtest.dll", + "args": [], + "cwd": "${workspaceFolder}", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..b2f5e46 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,41 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/langtest.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/langtest.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "--project", + "${workspaceFolder}/langtest.csproj" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/AST.cs b/AST.cs new file mode 100644 index 0000000..19f12e1 --- /dev/null +++ b/AST.cs @@ -0,0 +1,1509 @@ +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 variables=new Dictionary(); + + 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 expressions) + { + return state.ExecuteFunction(str,expressions); + } + + public bool HasFunction(string str) + { + return state.HasFunction(str); + } + + public void AddFunction(string str, List 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 expressions = new Dictionary(); + + + public Dictionary param,Expression expression)> methods=new Dictionary param, Expression expression)>(); + public Dictionary streams=new Dictionary(); + public Dictionary variables=new Dictionary(); + + public Dictionary,bool perm )> boxes = new Dictionary 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(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 expressions) + { + if(!HasFunction(str)) return 0; + var func=methods[str]; + var res=NewScope(); + for(int i = 0;i(text.Select((e)=>{return e;})),permanent)); + return i; + } + + public bool HasFunction(string str) + { + return methods.ContainsKey(str); + } + + public void AddFunction(string str, List 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 box = boxes[boxId].Item1; + byte[] data=box.Skip((int)offset).Take((int)len).Select((e)=>{ + return (byte)(e % byte.MaxValue); + }).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 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 expressions); + bool HasFunction(string str); + void AddFunction(string str,List 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 tokens) + { + int i = 0; + ParseNode(node,tokens,ref i,true); + } + public static ListNode Parse(List tokens) + { + int i = 0; + ListNode node=new ListNode(); + ParseNode(node,tokens,ref i,true); + return node; + } + public static void ParseNode(ListNode node,List tokens,ref int i,bool root=false) + { + node.Root=root; + + //i = 0 + //0 + //func() + + while(i 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 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 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 funcArgs = new List(); + //check whether its args + i++; + while(i -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 expressions; + public FunctionCallNode(string name,List 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 == "rshit") + { + 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; + Expression exp = expressions[3]; + if(stream_name == null) throw new Exception("You must use identifier at positional arg #3 (starting from 1)"); + string name = stream_name.Name; + //tcpserver("0.0.0.0",4202,strm,{}) + 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); + 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 args=new List(); + if(vgvn == null) throw new Exception("Name must be identifier"); + for(int i = 1;i 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 Nodes = new List(); + 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; + } + } +} \ No newline at end of file diff --git a/Lexer.cs b/Lexer.cs new file mode 100644 index 0000000..ba1b232 --- /dev/null +++ b/Lexer.cs @@ -0,0 +1,267 @@ +using System.Globalization; +using System.Text; + +namespace langtest +{ + public enum LexTokenType + { + PLUS=0, + MINUS=1, + MULTIPLY=2, + DIVIDE=3, + MOD=4, + LPAREN=5, + RPAREN=6, + IDENTIFER=7, + NUMBER=8, + EQUALS=9, + COMMA=10, + ERROR=11, + SEMI=12, + LBRACE=13, + RBRACE=14, + STRING=15, + } + + public class LexToken + { + public LexToken() + { + + } + public LexToken(string text) + { + Text = text; + Type=char.IsLetter(text.FirstOrDefault()) ? LexTokenType.IDENTIFER : (char.IsNumber(text.FirstOrDefault()) ? LexTokenType.NUMBER : LexTokenType.ERROR); + } + + public LexTokenType Type {get;set;} + public string Text {get;set;}=""; + } + + public static class Lexer + { + public static string? Prompt(string t) + { + Console.Write(t); + return Console.ReadLine(); + } + public static IEnumerable EnumerateTokens(string text) + { + int filePos=0; + Func<(char chr,bool esc)> read_char = ()=>{ + int txt=text[filePos++]; + + if(txt == '\\') + { + + //we are to escape + txt = text[filePos++]; + if(txt == 'x') + { + + char[] chars=new char[4]; + + + for(int i = 0 ;i<4;i++) + { + txt = text[filePos++]; + + chars[i] = (char)txt; + } + return ((char)Int16.Parse(new string(chars), NumberStyles.AllowHexSpecifier),true); + + }else{ + + if(txt == 'n') + { + return ('\n',true); + } + if(txt == 'r') + { + return ('\r',true); + } + if(txt == 't') + { + return ('\t',true); + } + return ((char)txt,true); + } + } + else{ + return ((char)txt,false); + } + }; + + Func read_string = ()=>{ + StringBuilder b=new StringBuilder(); + while(true) + { + (char chr,bool esc) txt=read_char(); + if(txt.chr == '\"' && !txt.esc) + { + break; + } + b.Append(txt.chr); + } + return b.ToString(); + }; + + StringBuilder b=new StringBuilder(); + while(filePos < text.Length) + { + char c=text[filePos++]; + + if(c == '\"') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + string str = read_string(); + yield return new LexToken(){Text = str,Type = LexTokenType.STRING}; + } + else + if(c == '\'') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + char str = read_char().chr; + filePos++; + yield return new LexToken(){Text = ((int)str).ToString(),Type = LexTokenType.NUMBER}; + }else + if(c == '+') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text="+",Type = LexTokenType.PLUS}; + }else + if(c == '-') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text="-",Type = LexTokenType.MINUS}; + }else + if(c == '*') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text="*",Type = LexTokenType.MULTIPLY}; + }else + if(c == '/') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text="/",Type = LexTokenType.DIVIDE}; + }else + if(c == '%') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text="%",Type = LexTokenType.MOD}; + }else if(c == '{') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text="{",Type = LexTokenType.LBRACE}; + }else if(c == '}') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text="}",Type = LexTokenType.RBRACE}; + } + else + if(c == '(') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text="(",Type = LexTokenType.LPAREN}; + }else + if(c == ')') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text=")",Type = LexTokenType.RPAREN}; + }else if(c == '=') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text="=",Type = LexTokenType.EQUALS}; + } + else if(c == ',') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text=",",Type = LexTokenType.COMMA}; + } + else if(c == ';') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + yield return new LexToken(){Text=";",Type = LexTokenType.SEMI}; + } + else if(c == '\n' || c == ' ' || c == '\t') + { + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + + + }else{ + b.Append(c); + } + + + } + if(b.Length > 0) + { + yield return new LexToken(b.ToString()); + b.Clear(); + } + + } + + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..208faf3 --- /dev/null +++ b/Program.cs @@ -0,0 +1,38 @@ +using langtest; +using Newtonsoft.Json; + +/* +var re=new ApplicationState(); +if(args.Length == 0) +{ +string? text; + +while((text=Lexer.Prompt("> ")) != null) +{ + var lexed=Lexer.EnumerateTokens(text); + + var res=Ast.Parse(lexed.ToList()); + + res.Execute(re); +} +}else{ + string text=File.ReadAllText(args[0]); + var lexed=Lexer.EnumerateTokens(text); + + var res=Ast.Parse(lexed.ToList()); + + res.Execute(re); +}*/ +var app = new ApplicationState(); +var ast = new ListNode(); +foreach(var file in Directory.GetFiles("code/dep","*",SearchOption.AllDirectories)) +{ + string text=File.ReadAllText(file); + var lexed=Lexer.EnumerateTokens(text); + + Ast.Parse(ast,lexed.ToList()); +} +string text2=File.ReadAllText("code/app.bs"); +var lexed2=Lexer.EnumerateTokens(text2); +Ast.Parse(ast,lexed2.ToList()); +ast.Execute(app); \ No newline at end of file diff --git a/boxscript.bs b/boxscript.bs new file mode 100644 index 0000000..421dda9 --- /dev/null +++ b/boxscript.bs @@ -0,0 +1,18 @@ +create_function(box_addrange,mybox,boxToAppend,{ + cur.i = 0; + cur.len =box_len(boxToAppend); + for(cur.i,cur.len,cur.i+1,{ + box_add(mybox,box_getvalue(boxToAppend,i)); + }); +}); + +box_print("Type youtube url: "); + +connection=tcp_client("192.168.0.142",3252); +res = box_create(); +box_addrange(res,"GET /api/AddItem/"); +box_addrange(res,box_readline()); +box_addrange(res,"HTTP/1.1\r\nHost: 192.168.0.142:3252\r\n\r\n"); + +stream_write(connection,res,0,box_len(res)); +stream_close(connection); \ No newline at end of file diff --git a/code/app.bs b/code/app.bs new file mode 100644 index 0000000..d6d64fd --- /dev/null +++ b/code/app.bs @@ -0,0 +1,5 @@ +res=string_split_chr("Demi,Lovato,Tom,Joel",','); +j=0; +for(j,box_len(res),j+1,{ + box_println(box_getvalue(res,j)); +}); \ No newline at end of file diff --git a/code/dep/string_split.bs b/code/dep/string_split.bs new file mode 100644 index 0000000..964a153 --- /dev/null +++ b/code/dep/string_split.bs @@ -0,0 +1,22 @@ +create_function(string_split_chr,boxId,string_split_chr_chr,{ + box=box_create(); + + box2 = box_create(); + split_str_chr_i = 0; + for(split_str_chr_i,box_len(boxId),split_str_chr_i+1,{ + if(eq(box_getvalue(boxId,split_str_chr_i),string_split_chr_chr),{ + if(box_len(box2),{ + box_add(box,box2); + box2 = box_create(); + },0); + },{ + box_add(box2,box_getvalue(boxId,split_str_chr_i)); + }); + }); + if(box_len(box2),{ + box_add(box,box2); + box2 = box_create(); + },0); + + box; +}); \ No newline at end of file diff --git a/http.bs b/http.bs new file mode 100644 index 0000000..e69de29 diff --git a/langtest.csproj b/langtest.csproj new file mode 100644 index 0000000..018a8a9 --- /dev/null +++ b/langtest.csproj @@ -0,0 +1,14 @@ + + + + Exe + net6.0 + enable + enable + + + + + + +