diff --git a/ByteCodeTest/.vscode/launch.json b/ByteCodeTest/.vscode/launch.json
new file mode 100644
index 0000000..3f4f16f
--- /dev/null
+++ b/ByteCodeTest/.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/dotnet/vscode-csharp/blob/main/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/net7.0/ByteCodeTest.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/ByteCodeTest/.vscode/tasks.json b/ByteCodeTest/.vscode/tasks.json
new file mode 100644
index 0000000..b58c8df
--- /dev/null
+++ b/ByteCodeTest/.vscode/tasks.json
@@ -0,0 +1,41 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/ByteCodeTest.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/ByteCodeTest.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "--project",
+ "${workspaceFolder}/ByteCodeTest.csproj"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/ByteCodeTest/ByteCodeTest.csproj b/ByteCodeTest/ByteCodeTest.csproj
new file mode 100644
index 0000000..78c6818
--- /dev/null
+++ b/ByteCodeTest/ByteCodeTest.csproj
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/ByteCodeTest/Program.cs b/ByteCodeTest/Program.cs
new file mode 100644
index 0000000..70f4443
--- /dev/null
+++ b/ByteCodeTest/Program.cs
@@ -0,0 +1,10 @@
+using TLang.BytecodeCompiler;
+using TLang.Common;
+using TLang.Parser;
+
+
+var res=Parse.ParseFromFiles("app.tlang");
+using(var f = File.Create("app.tvm"))
+{
+ ByteCodeGenerator.GenerateToStream(res,f,new TLangVersion(1,0,0,0),new TLangVersion(1,0,0,0));
+}
\ No newline at end of file
diff --git a/ByteCodeTest/app.tlang b/ByteCodeTest/app.tlang
new file mode 100644
index 0000000..e73eeae
--- /dev/null
+++ b/ByteCodeTest/app.tlang
@@ -0,0 +1 @@
+37+5;
\ No newline at end of file
diff --git a/ByteCodeTest/app.tvm b/ByteCodeTest/app.tvm
new file mode 100644
index 0000000..3817887
Binary files /dev/null and b/ByteCodeTest/app.tvm differ
diff --git a/TLang.BytecodeCompiler/Class1.cs b/TLang.BytecodeCompiler/Class1.cs
new file mode 100644
index 0000000..745d2e3
--- /dev/null
+++ b/TLang.BytecodeCompiler/Class1.cs
@@ -0,0 +1,648 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using TLang.Parser;
+using TLang.Common;
+
+namespace TLang.BytecodeCompiler
+{
+
+ public class ByteCodeGenerator
+ {
+ private int I = 0;
+ public int NextNumber()
+ {
+ return I++;
+ }
+ public ByteCodeGenerator()
+ {
+ Chunks.Add(RootChunk);
+ }
+
+ public List Classes {get;set;}=new List();
+ public List Functions {get;set;}=new List();
+ public BytecodeChunk RootChunk = new BytecodeChunk();
+ public List Chunks {get;set;}=new List();
+
+ public static void GenerateToStream(Node node,Stream strm,TLangVersion vmVersion,TLangVersion version,params TLangDependency[] dependencies)
+ {
+ ByteCodeGenerator gen=new ByteCodeGenerator();
+ gen._generateFile(node,strm,vmVersion,version,dependencies);
+ }
+
+ private void _generateFile(Node node,Stream strm,TLangVersion vmVersion,TLangVersion version,TLangDependency[] dependencies)
+ {
+ byte[] data = new byte[]{(byte)'T',(byte)'V',(byte)'M',vmVersion.Major,vmVersion.Minor,vmVersion.Patch,vmVersion.Build,version.Major,version.Minor,version.Patch,version.Build};
+ strm.Write(data,0,data.Length);
+ WriteBigEndianInt(strm,dependencies.Length);
+ foreach(var item in dependencies)
+ {
+ byte[] bytes = System.Text.Encoding.UTF8.GetBytes(item.Name);
+ WriteBigEndianInt(strm,bytes.Length);
+ strm.Write(bytes,0,bytes.Length);
+ byte[] dependV = new byte[]{item.Version.Major,item.Version.Minor,item.Version.Patch,item.Version.Build};
+ strm.Write(dependV,0,dependV.Length);
+ }
+
+ GenerateCode(node,RootChunk,0,0,-1,-1,true);
+ WriteBigEndianInt(strm,Functions.Count);
+ foreach(var item in Functions)
+ {
+ int closure = Chunks.Count;
+ BytecodeChunk _chunk = new BytecodeChunk();
+ _chunk.Arguments = item.ClosureNode.Arguments;
+ Chunks.Add(_chunk);
+ GenerateCode(item.ClosureNode.Node,_chunk,0,0,-1,-1,false);
+
+
+ byte[] bytes = System.Text.Encoding.UTF8.GetBytes(item.FunctionName);
+ WriteBigEndianInt(strm,bytes.Length);
+ strm.Write(bytes,0,bytes.Length);
+ WriteBigEndianInt(strm,closure);
+ }
+
+ WriteBigEndianInt(strm,Classes.Count);
+ foreach(var item in Classes)
+ {
+ byte[] bytes = System.Text.Encoding.UTF8.GetBytes(item.Name);
+ WriteBigEndianInt(strm,bytes.Length);
+ strm.Write(bytes,0,bytes.Length);
+
+ bytes = System.Text.Encoding.UTF8.GetBytes(item.InheritsFrom);
+ WriteBigEndianInt(strm,bytes.Length);
+ strm.Write(bytes,0,bytes.Length);
+ WriteBigEndianInt(strm,item.Entries.Count);
+
+ foreach(var classEntry in item.Entries)
+ {
+ var cValue = classEntry.InitialValue as ClosureNode;
+ if(cValue != null)
+ {
+ byte c = 0b00000100;
+ if(classEntry.Abstract) { c |= 0b00001000;}
+ if(classEntry.Modifier == "prot") {c |= 0b00000001;}
+ if(classEntry.Modifier == "pub") {c |= 0b00000010;}
+ strm.WriteByte(c);
+ bytes = System.Text.Encoding.UTF8.GetBytes(classEntry.Name);
+ WriteBigEndianInt(strm,bytes.Length);
+ strm.Write(bytes,0,bytes.Length);
+ int closure = Chunks.Count;
+ BytecodeChunk _chunk = new BytecodeChunk();
+ _chunk.Arguments = cValue.Arguments;
+ GenerateCode(cValue.Node,_chunk,0,0,-1,-1,false);
+ Chunks.Add(_chunk);
+ WriteBigEndianInt(strm,closure);
+ }
+ else
+ {
+ byte c = 0b00000100;
+
+ if(classEntry.Modifier == "prot") {c |= 0b00000001;}
+ if(classEntry.Modifier == "pub") {c |= 0b00000010;}
+ strm.WriteByte(c);
+ bytes = System.Text.Encoding.UTF8.GetBytes(classEntry.Name);
+ WriteBigEndianInt(strm,bytes.Length);
+ strm.Write(bytes,0,bytes.Length);
+ int closure = Chunks.Count;
+ BytecodeChunk _chunk = new BytecodeChunk();
+
+ GenerateCode(new ReturnNode(classEntry.InitialValue),_chunk,0,0,-1,-1,false);
+ Chunks.Add(_chunk);
+ WriteBigEndianInt(strm,closure);
+ }
+ }
+ }
+
+ WriteBigEndianInt(strm,Chunks.Count);
+ foreach(var item in Chunks)
+ {
+ item.SetLabelable();
+ WriteBigEndianInt(strm,item.Arguments.Count);
+ foreach(var arg in item.Arguments)
+ {
+ byte[] bytes = System.Text.Encoding.UTF8.GetBytes(arg);
+ WriteBigEndianInt(strm,bytes.Length);
+ strm.Write(bytes,0,bytes.Length);
+ }
+ WriteBigEndianInt(strm,item.CurrentByteLength);
+ foreach(var instruction in item.Instructions)
+ {
+ instruction.WriteData(strm);
+ }
+ }
+ }
+
+ private void WriteBigEndianInt(Stream strm, int count)
+ {
+ byte[] data = BitConverter.GetBytes(count);
+ if(BitConverter.IsLittleEndian) Array.Reverse(data);
+ strm.Write(data,0,data.Length);
+ }
+
+ public void GenerateCode(Node node,BytecodeChunk chunk,int scopeIndex,int scopeBreakIndex,int _labelBeginningLoop,int _labelEndLoop,bool isRoot=false)
+ {
+ var funcDec = node as FunctionDeclaritionNode;
+ var chrNode = node as CharNode;
+ var strNode = node as StringNode;
+ var dblNode = node as ConstNumberNode;
+ var clsDec = node as ClassNode;
+ var addNode = node as AddNode;
+ var subNode = node as SubtractNode;
+ var timesNode = node as MultiplyNode;
+ var divNode = node as DivideNode;
+ var modNode = node as ModuloNode;
+ var powNode = node as PowNode;
+ var lshiftNode = node as LeftShiftNode;
+ var rshiftNode = node as RightShiftNode;
+ var bOrNode = node as BOrNode;
+ var bAndNode = node as BAndNode;
+ var xOrNode = node as XOrNode;
+ var negNode = node as NegativeNode;
+ var bNotNode = node as BitwiseNotNode;
+
+ var nEqNode = node as NotEqualsNode;
+ var eqNode = node as EqualsNode;
+ var lOrNode = node as LOrNode;
+ var lAndNode = node as LAndNode;
+ var ltNode = node as LessThanNode;
+ var lteNode = node as LessThanEqualsNode;
+ var gtNode = node as GreaterThanNode;
+ var gteNode = node as GreaterThanEqualsNode;
+ var notNode = node as NotNode;
+
+ var scNode = node as ScopeNode;
+ var retNode = node as ReturnNode;
+ var closureNode = node as ClosureNode;
+ var whileNode = node as WhileLoop;
+ var eachNode = node as EachLoopNode;
+ var forNode = node as ForLoopNode;
+ var ifNode = node as IfNode;
+ var functionCallNode = node as FunctionCallNode;
+ var methodCallNode = node as MethodCallNode;
+ var getVariableNode = node as GetVariableNode;
+ var getMemberNode = node as GetMemberNode;
+ var getArrayValue = node as GetArrayNode;
+ var setVariableNode = node as SetVariableNode;
+
+
+ if(scNode != null)
+ {
+ if(scNode.IsSwitchScope)
+ {
+ int caseNumber = NextNumber();
+ int labelNumEnd = NextNumber();
+ int caseNo2=0;
+
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_BEGIN));
+ bool hasDefault =false;
+ bool beforeCase=true;
+ foreach(var item in scNode.Nodes)
+ {
+ var c = item as CaseNode;
+ var d = item as DefaultNode;
+ if(c != null)
+ {
+ beforeCase = false;
+ EqualsNode equals=new EqualsNode(scNode.SwitchCondition,c.Variable);
+ GenerateCode(equals,chunk,scopeIndex+1,0,_labelBeginningLoop,labelNumEnd,false);
+ JumpConditional unconditional = new JumpConditional($"_case{caseNumber}_{caseNo2}");
+ chunk.Add(unconditional);
+
+ caseNo2++;
+ }
+ if(d != null)
+ {
+ hasDefault =false;
+ beforeCase = false;
+ JumpUnconditional unconditional = new JumpUnconditional($"_default{caseNumber}");
+ chunk.Add(unconditional);
+ }
+ if(beforeCase)
+ {
+ GenerateCode(item,chunk,scopeIndex+1,0,_labelBeginningLoop,_labelEndLoop,isRoot);
+ }
+ }
+ if(!hasDefault)
+ {
+ JumpUnconditional unconditional = new JumpUnconditional($"_label{labelNumEnd}");
+ chunk.Add(unconditional);
+ }
+
+ beforeCase=true;
+ caseNo2=0;
+ foreach(var item in scNode.Nodes)
+ {
+ var c = item as CaseNode;
+ var d = item as DefaultNode;
+ if(c != null)
+ {
+ beforeCase = false;
+ LabelInstruction instruction = new LabelInstruction($"_case{caseNumber}_{caseNo2}");
+ chunk.Add(instruction);
+ caseNo2++;
+ }
+
+ if(d != null)
+ {
+ beforeCase = false;
+ LabelInstruction instruction = new LabelInstruction($"_default{caseNumber}");
+ chunk.Add(instruction);
+ }
+
+ if(!beforeCase && c == null && d == null)
+ {
+ GenerateCode(item,chunk,scopeIndex+1,scopeBreakIndex,_labelBeginningLoop,labelNumEnd,scNode.RootScope);
+ }
+ }
+ LabelInstruction endLabel = new LabelInstruction($"_label{labelNumEnd}");
+ chunk.Add(endLabel);
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_END));
+ }
+ else
+ {
+ if(!scNode.RootScope)
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_BEGIN));
+ foreach(var item in scNode.Nodes)
+ {
+ GenerateCode(item,chunk,scopeIndex+1,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,scNode.RootScope);
+ }
+ if(!scNode.RootScope)
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_END));
+ }
+
+ }
+ if(ifNode != null)
+ {
+ int labelNumNo = NextNumber();
+ int labelNumEnd = NextNumber();
+ GenerateCode(new NotNode(ifNode.Condition),chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ JumpConditional jc=new JumpConditional($"_label{labelNumNo}");
+ chunk.Add(jc);
+ GenerateCode(ifNode.Yes,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ JumpUnconditional ju = new JumpUnconditional($"_label{labelNumEnd}");
+ chunk.Add(ju);
+ LabelInstruction labelNo = new LabelInstruction($"_label{labelNumNo}");
+ chunk.Add(labelNo);
+ GenerateCode(ifNode.No,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ LabelInstruction labelEnd = new LabelInstruction($"_label{labelNumEnd}");
+ chunk.Add(labelEnd);
+ }
+ if(bNotNode != null)
+ {
+ GenerateCode(bNotNode.Node,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.BNOT));
+ }
+ if(negNode != null)
+ {
+ GenerateCode(negNode.Node,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.NEG));
+ }
+ if(notNode != null)
+ {
+ GenerateCode(notNode.Node,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.LNOT));
+ }
+ if(eachNode != null)
+ {
+ int ittrVarNum = NextNumber();
+ int labelNum = NextNumber();
+ int labelNumEnd = NextNumber();
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_BEGIN));
+
+ GetVariableNode variableNode=new GetVariableNode($"__compGen{ittrVarNum}");
+ var member= new GetMemberNode(eachNode.Itterator,"ittr");
+ SetVariableNode variableNode1=new SetVariableNode(variableNode,member);
+ GenerateCode(variableNode1,chunk,scopeIndex+1,0,_labelBeginningLoop,_labelEndLoop,false);
+ LabelInstruction labelNode=new LabelInstruction($"_label{labelNum}");
+ chunk.Add(labelNode);
+
+ JumpConditional conditional = new JumpConditional($"_label{labelNumEnd}");
+ chunk.Add(conditional);
+
+ SetVariableNode variableNode2=new SetVariableNode(eachNode.Name,new NotNode(new MethodCallNode(variableNode,"movenext")));
+ GenerateCode(variableNode2,chunk,scopeIndex+1,0,labelNum,labelNumEnd,false);
+ GenerateCode(eachNode.Body,chunk,scopeIndex+1,0,labelNum,labelNumEnd,false);
+
+ JumpUnconditional juC=new JumpUnconditional($"_label{labelNum}");
+ chunk.Add(juC);
+ LabelInstruction endLabel = new LabelInstruction($"_label{labelNumEnd}");
+ chunk.Add(endLabel);
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_END));
+ }
+ if(forNode != null)
+ {
+ int labelNum = NextNumber();
+ int labelNumEnd = NextNumber();
+
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_BEGIN));
+ GenerateCode(forNode.Init,chunk,scopeIndex+1,0,labelNum,labelNumEnd,false);
+ LabelInstruction labelNode=new LabelInstruction($"_label{labelNum}");
+ chunk.Add(labelNode);
+
+ GenerateCode(new NotNode(forNode.Condition),chunk,scopeIndex+1,0,labelNum,labelNumEnd,false);
+ JumpConditional conditional = new JumpConditional($"_label{labelNumEnd}");
+ chunk.Add(conditional);
+
+ GenerateCode(forNode.Body,chunk,scopeIndex+1,0,labelNum,labelNumEnd,false);
+ GenerateCode(forNode.Increment,chunk,scopeIndex+1,0,labelNum,labelNumEnd,false);
+ JumpUnconditional juC=new JumpUnconditional($"_label{labelNum}");
+ chunk.Add(juC);
+ LabelInstruction endLabel = new LabelInstruction($"_label{labelNumEnd}");
+ chunk.Add(endLabel);
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_END));
+ }
+ if(whileNode != null)
+ {
+ int labelNum = NextNumber();
+ int labelNumEnd = NextNumber();
+
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_BEGIN));
+ LabelInstruction labelNode=new LabelInstruction($"_label{labelNum}");
+ chunk.Add(labelNode);
+ if(whileNode.IsDo)
+ {
+ GenerateCode(whileNode.Body,chunk,scopeIndex+1,0,labelNum,labelNumEnd,false);
+ GenerateCode(new NotNode(whileNode.Condition),chunk,scopeIndex+1,0,labelNum,labelNumEnd,false);
+ JumpConditional conditional = new JumpConditional($"_label{labelNum}");
+ chunk.Add(conditional);
+ }
+ else
+ {
+ GenerateCode(new NotNode(whileNode.Condition),chunk,scopeIndex+1,0,labelNum,labelNumEnd,false);
+ JumpConditional conditional = new JumpConditional($"_label{labelNumEnd}");
+ chunk.Add(conditional);
+
+ GenerateCode(whileNode.Body,chunk,scopeIndex+1,0,labelNum,labelNumEnd,false);
+ JumpUnconditional juC=new JumpUnconditional($"_label{labelNum}");
+ chunk.Add(juC);
+ }
+
+ LabelInstruction endLabel = new LabelInstruction($"_label{labelNumEnd}");
+ chunk.Add(endLabel);
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_END));
+ }
+ if(node is ContinueNode && _labelBeginningLoop >= 0)
+ {
+ for(int i = scopeBreakIndex;i>0;i--)
+ {
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_END));
+ }
+ JumpUnconditional conditional=new JumpUnconditional($"_label{_labelBeginningLoop}");
+ chunk.Add(conditional);
+ }
+ if(node is BreakNode && _labelEndLoop >= 0)
+ {
+ for(int i = scopeBreakIndex;i>0;i--)
+ {
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_END));
+ }
+ JumpUnconditional conditional=new JumpUnconditional($"_label{_labelEndLoop}");
+ chunk.Add(conditional);
+ }
+ if(closureNode != null)
+ {
+ BytecodeChunk _chunk = new BytecodeChunk();
+ _chunk.Arguments = closureNode.Arguments;
+ GenerateCode(closureNode.Node,_chunk,0,0,-1,-1,false);
+ int i = Chunks.Count;
+ Chunks.Add(_chunk);
+ chunk.Add(new PushClosureNode(i));
+ }
+ if(node is NullNode)
+ {
+ chunk.Add(new SimpleInstruction(Instruction.PUSH_NULL));
+ }
+ if(node is UndefinedNode)
+ {
+ chunk.Add(new SimpleInstruction(Instruction.PUSH_UNDEFINED));
+ }
+ if(node is TrueNode)
+ {
+ chunk.Add(new SimpleInstruction(Instruction.PUSH_TRUE));
+ }
+ if(node is FalseNode)
+ {
+ chunk.Add(new SimpleInstruction(Instruction.PUSH_FALSE));
+ }
+ if(chrNode != null)
+ {
+ chunk.Add(new PushCharNode(chrNode.Text));
+ }
+ if(strNode != null)
+ {
+ chunk.Add(new PushStringInstruction(strNode.Text));
+ }
+ if(dblNode != null)
+ {
+ chunk.Add(new PushDoubleInstruction(dblNode.Value));
+ }
+
+ if(funcDec != null)
+ {
+ if(isRoot)
+ {
+ Functions.Add(funcDec);
+ }
+ else
+ {
+ SetVariableNode variableNode=new SetVariableNode(new GetVariableNode(funcDec.FunctionName),funcDec.ClosureNode) {LineInfo = funcDec.LineInfo};
+ GenerateCode(variableNode,chunk,scopeIndex,scopeBreakIndex,-1,-1,false);
+ }
+ }
+ if(clsDec != null)
+ {
+ Classes.Add(clsDec);
+ }
+ if(addNode != null)
+ {
+ GenerateCode(addNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(addNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.ADD));
+ }
+ if(subNode != null)
+ {
+ GenerateCode(subNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(subNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.SUB));
+ }
+ if(timesNode != null)
+ {
+ GenerateCode(timesNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(timesNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.TIMES));
+ }
+ if(divNode != null)
+ {
+ GenerateCode(divNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(divNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.DIVIDE));
+ }
+ if(modNode != null)
+ {
+ GenerateCode(modNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(modNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.MOD));
+ }
+ if(powNode != null)
+ {
+ GenerateCode(powNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(powNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.POW));
+ }
+ if(lshiftNode != null)
+ {
+ GenerateCode(lshiftNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(lshiftNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.LSHIFT));
+ }
+ if(rshiftNode != null)
+ {
+ GenerateCode(rshiftNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(rshiftNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.RSHIFT));
+ }
+ if(bOrNode != null)
+ {
+ GenerateCode(bOrNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(bOrNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.BOR));
+ }
+ if(bAndNode != null)
+ {
+ GenerateCode(bAndNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(bAndNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.BAND));
+ }
+ if(xOrNode != null)
+ {
+ GenerateCode(xOrNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(xOrNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.XOR));
+ }
+ if(nEqNode != null)
+ {
+ GenerateCode(nEqNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(nEqNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.NEQ));
+ }
+ if(eqNode != null)
+ {
+ GenerateCode(eqNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(eqNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.EQ));
+ }
+ if(lOrNode != null)
+ {
+ GenerateCode(lOrNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(lOrNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.LOR));
+ }
+ if(lAndNode != null)
+ {
+ GenerateCode(lAndNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(lAndNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.LAND));
+ }
+ if(ltNode != null)
+ {
+ GenerateCode(ltNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(ltNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.LT));
+ }
+ if(lteNode != null)
+ {
+ GenerateCode(lteNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(lteNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.LTE));
+ }
+ if(gtNode != null)
+ {
+ GenerateCode(gtNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(gtNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.GT));
+ }
+ if(gteNode != null)
+ {
+ GenerateCode(gteNode.Left,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(gteNode.Right,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.GTE));
+ }
+ if(retNode != null)
+ {
+ GenerateCode(retNode.Expression,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ for(int i = scopeIndex;i>0;i--)
+ {
+ chunk.Add(new SimpleInstruction(Instruction.SCOPE_END));
+ }
+ chunk.Add(new SimpleInstruction(Instruction.RET));
+ }
+ if(methodCallNode != null)
+ {
+
+ GenerateCode(methodCallNode.Symbol,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new PushStringInstruction(methodCallNode.Name));
+ foreach(var arg in methodCallNode.Arguments)
+ {
+ GenerateCode(arg,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ }
+ chunk.Add(new PushDoubleInstruction(methodCallNode.Arguments.Count));
+ chunk.Add(new SimpleInstruction(Instruction.CALL_METHOD));
+ }
+ if(functionCallNode != null)
+ {
+ chunk.Add(new PushStringInstruction(functionCallNode.Name));
+ foreach(var arg in functionCallNode.Arguments)
+ {
+ GenerateCode(arg,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ }
+ chunk.Add(new PushDoubleInstruction(functionCallNode.Arguments.Count));
+ chunk.Add(new SimpleInstruction(Instruction.CALL_FUNC));
+ }
+ if(getVariableNode != null)
+ {
+ chunk.Add(new PushStringInstruction(getVariableNode.Name));
+ chunk.Add(new SimpleInstruction(Instruction.PUSH_VARIABLE_VALUE));
+ }
+ if(getMemberNode != null)
+ {
+ GenerateCode(getMemberNode.Symbol,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new PushStringInstruction(getMemberNode.Name));
+ chunk.Add(new SimpleInstruction(Instruction.PUSH_FIELD_VALUE));
+ }
+ if(getArrayValue != null)
+ {
+ GenerateCode(getArrayValue.Symbol,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(getArrayValue.Expression,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.PUSH_ARRAY_VALUE));
+ }
+
+ if(setVariableNode != null)
+ {
+ var gVN = setVariableNode.SetTo as GetVariableNode;
+ var gMN = setVariableNode.SetTo as GetMemberNode;
+ var gAN = setVariableNode.SetTo as GetArrayNode;
+ if(gVN != null)
+ {
+ chunk.Add(new PushStringInstruction(gVN.Name));
+ GenerateCode(setVariableNode.Expression,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.POP_VARIABLE_VALUE));
+ }
+ if(gMN != null)
+ {
+ GenerateCode(gMN.Symbol,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new PushStringInstruction(gMN.Name));
+ GenerateCode(setVariableNode.Expression,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.POP_FIELD_VALUE));
+ }
+ if(gAN != null)
+ {
+ GenerateCode(gAN.Symbol,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(gAN.Expression,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ GenerateCode(setVariableNode.Expression,chunk,scopeIndex,scopeBreakIndex,_labelBeginningLoop,_labelEndLoop,isRoot);
+ chunk.Add(new SimpleInstruction(Instruction.POP_ARRAY_VALUE));
+ }
+ }
+ }
+
+ }
+}
diff --git a/TLang.BytecodeCompiler/TLang.BytecodeCompiler.csproj b/TLang.BytecodeCompiler/TLang.BytecodeCompiler.csproj
new file mode 100644
index 0000000..3f1cc94
--- /dev/null
+++ b/TLang.BytecodeCompiler/TLang.BytecodeCompiler.csproj
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+ netstandard2.0
+
+
+
diff --git a/TLang.Common/BytecodeChunk.cs b/TLang.Common/BytecodeChunk.cs
new file mode 100644
index 0000000..5d0285c
--- /dev/null
+++ b/TLang.Common/BytecodeChunk.cs
@@ -0,0 +1,33 @@
+using System.Collections.Generic;
+using TLang.Common;
+
+namespace TLang.Common
+{
+ public class BytecodeChunk
+ {
+ public int CurrentByteLength {get;set;}=0;
+ public void Add(Instruction instruction)
+ {
+ var i = instruction as LabelInstruction;
+ if(i != null) Offsets.Add(i.Key,CurrentByteLength);
+ else {
+ CurrentByteLength += instruction.CalculateLength();
+ Instructions.Add(instruction);
+ }
+ }
+ public void SetLabelable()
+ {
+ foreach(var item in Instructions)
+ {
+ var item2 = item as ILabelable;
+ if(item2 != null)
+ {
+ if(Offsets.ContainsKey(item2.Key)) item2.Value = Offsets[item2.Key];
+ }
+ }
+ }
+ public Dictionary Offsets {get;set;}=new Dictionary();
+ public List Arguments {get;set;}=new List();
+ public List Instructions {get;set;}=new List();
+ }
+}
diff --git a/TLang.Common/ILabelable.cs b/TLang.Common/ILabelable.cs
new file mode 100644
index 0000000..e36496e
--- /dev/null
+++ b/TLang.Common/ILabelable.cs
@@ -0,0 +1,8 @@
+namespace TLang.Common
+{
+ public interface ILabelable
+ {
+ string Key {get;set;}
+ int Value {get;set;}
+ }
+}
diff --git a/TLang.Common/Instruction.cs b/TLang.Common/Instruction.cs
new file mode 100644
index 0000000..081cdba
--- /dev/null
+++ b/TLang.Common/Instruction.cs
@@ -0,0 +1,71 @@
+using System.IO;
+
+namespace TLang.Common
+{
+ public abstract class Instruction
+ {
+ public abstract int CalculateLength();
+
+ public abstract void WriteData(Stream strm);
+
+
+ public const byte ADD = 0x00;
+ public const byte SUB = 0x01;
+ public const byte TIMES = 0x02;
+ public const byte DIVIDE = 0x03;
+ public const byte MOD = 0x04;
+
+ public const byte POW = 0x05;
+
+ public const byte LSHIFT = 0x06;
+ public const byte RSHIFT = 0x07;
+ public const byte BOR = 0x08;
+ public const byte BAND = 0x09;
+ public const byte XOR = 0x0A;
+
+ public const byte NEG = 0x0B;
+ public const byte BNOT = 0x0C;
+
+ public const byte NEQ = 0x10;
+ public const byte EQ = 0x11;
+
+ public const byte LOR = 0x12;
+
+ public const byte LAND = 0x13;
+
+ public const byte LNOT = 0x14;
+
+ public const byte LT = 0x15;
+ public const byte LTE = 0x16;
+ public const byte GT = 0x17;
+ public const byte GTE = 0x18;
+
+
+ public const byte SCOPE_BEGIN = 0xEA;
+ public const byte SCOPE_END = 0xEB;
+ public const byte CALL_FUNC = 0xEC;
+ public const byte CALL_METHOD = 0xED;
+ public const byte JMP = 0xEE;
+ public const byte JMPC = 0xEF;
+
+ public const byte POP_ARRAY_VALUE = 0xF0;
+ public const byte PUSH_ARRAY_VALUE = 0xF1;
+
+ public const byte POP_FIELD_VALUE = 0xF2;
+ public const byte PUSH_FIELD_VALUE = 0xF3;
+ public const byte POP_VARIABLE_VALUE = 0xF4;
+ public const byte PUSH_VARIABLE_VALUE = 0xF5;
+ public const byte PUSH_CHAR = 0xF6;
+ public const byte PUSH_FALSE = 0xF7;
+ public const byte PUSH_TRUE = 0xF8;
+ public const byte PUSH_UNDEFINED = 0xF9;
+ public const byte PUSH_NULL = 0xFA;
+ public const byte PUSH_CLOSURE = 0xFB;
+ public const byte PUSH_STRING = 0xFC;
+ public const byte PUSH_DOUBLE = 0xFD;
+ public const byte NOP = 0xFE;
+ public const byte RET = 0xFF;
+
+
+ }
+}
\ No newline at end of file
diff --git a/TLang.Common/JumpConditional.cs b/TLang.Common/JumpConditional.cs
new file mode 100644
index 0000000..267375a
--- /dev/null
+++ b/TLang.Common/JumpConditional.cs
@@ -0,0 +1,28 @@
+using System;
+using System.IO;
+
+namespace TLang.Common
+{
+ public class JumpConditional : Instruction, ILabelable
+ {
+ public string Key {get;set;}="";
+ public int Value {get;set;} =0;
+ public JumpConditional(string key)
+ {
+ Key = key;
+ }
+
+ public override int CalculateLength()
+ {
+ return 5;
+ }
+
+ public override void WriteData(Stream strm)
+ {
+ strm.WriteByte(JMPC);
+ var data=BitConverter.GetBytes(Value);
+ if(BitConverter.IsLittleEndian) Array.Reverse(data);
+ strm.Write(data,0,data.Length);
+ }
+ }
+}
diff --git a/TLang.Common/JumpUnconditional.cs b/TLang.Common/JumpUnconditional.cs
new file mode 100644
index 0000000..d976794
--- /dev/null
+++ b/TLang.Common/JumpUnconditional.cs
@@ -0,0 +1,28 @@
+using System;
+using System.IO;
+
+namespace TLang.Common
+{
+ public class JumpUnconditional : Instruction, ILabelable
+ {
+ public string Key {get;set;}
+ public int Value {get;set;} =0;
+ public JumpUnconditional(string key)
+ {
+ Key = key;
+ }
+
+ public override int CalculateLength()
+ {
+ return 5;
+ }
+
+ public override void WriteData(Stream strm)
+ {
+ strm.WriteByte(JMP);
+ var data=BitConverter.GetBytes(Value);
+ if(BitConverter.IsLittleEndian) Array.Reverse(data);
+ strm.Write(data,0,data.Length);
+ }
+ }
+}
diff --git a/TLang.Common/LabelInstruction.cs b/TLang.Common/LabelInstruction.cs
new file mode 100644
index 0000000..5e233a0
--- /dev/null
+++ b/TLang.Common/LabelInstruction.cs
@@ -0,0 +1,24 @@
+using System.IO;
+
+namespace TLang.Common
+{
+ public class LabelInstruction : Instruction
+ {
+ public string Key {get;set;}
+
+ public LabelInstruction(string key)
+ {
+ Key = key;
+ }
+
+ public override int CalculateLength()
+ {
+ return 0;
+ }
+
+ public override void WriteData(Stream strm)
+ {
+
+ }
+ }
+}
diff --git a/TLang.Common/PushCharNode.cs b/TLang.Common/PushCharNode.cs
new file mode 100644
index 0000000..e935eb9
--- /dev/null
+++ b/TLang.Common/PushCharNode.cs
@@ -0,0 +1,26 @@
+using System.IO;
+using TLang.Common;
+
+namespace TLang.BytecodeCompiler
+{
+ public class PushCharNode : Instruction
+ {
+ public char Text {get;set;}
+
+ public PushCharNode(char text)
+ {
+ Text = text;
+ }
+
+ public override int CalculateLength()
+ {
+ return 2;
+ }
+
+ public override void WriteData(Stream strm)
+ {
+ strm.WriteByte(PUSH_CHAR);
+ strm.WriteByte((byte)Text);
+ }
+ }
+}
\ No newline at end of file
diff --git a/TLang.Common/PushClosureNode.cs b/TLang.Common/PushClosureNode.cs
new file mode 100644
index 0000000..13c08d6
--- /dev/null
+++ b/TLang.Common/PushClosureNode.cs
@@ -0,0 +1,28 @@
+using System;
+using System.IO;
+using TLang.Common;
+
+namespace TLang.Common
+{
+ public class PushClosureNode : Instruction
+ {
+ public int Value {get;set;}
+ public PushClosureNode(int i)
+ {
+ Value = i;
+ }
+
+ public override int CalculateLength()
+ {
+ return 5;
+ }
+
+ public override void WriteData(Stream strm)
+ {
+ strm.WriteByte(PUSH_CLOSURE);
+ var data=BitConverter.GetBytes(Value);
+ if(BitConverter.IsLittleEndian) Array.Reverse(data);
+ strm.Write(data,0,data.Length);
+ }
+ }
+}
\ No newline at end of file
diff --git a/TLang.Common/PushDouble.cs b/TLang.Common/PushDouble.cs
new file mode 100644
index 0000000..b85ef18
--- /dev/null
+++ b/TLang.Common/PushDouble.cs
@@ -0,0 +1,29 @@
+using System;
+using System.IO;
+
+using TLang.Common;
+
+namespace TLang.BytecodeCompiler
+{
+ public class PushDoubleInstruction : Instruction
+ {
+ public double Value {get;set;}
+ public PushDoubleInstruction(double value)
+ {
+ Value = value;
+ }
+
+ public override int CalculateLength()
+ {
+ return 9;
+ }
+
+ public override void WriteData(Stream strm)
+ {
+ strm.WriteByte(PUSH_DOUBLE);
+ var data=BitConverter.GetBytes(Value);
+ if(BitConverter.IsLittleEndian) Array.Reverse(data);
+ strm.Write(data,0,data.Length);
+ }
+ }
+}
diff --git a/TLang.Common/PushStringInstruction.cs b/TLang.Common/PushStringInstruction.cs
new file mode 100644
index 0000000..f838303
--- /dev/null
+++ b/TLang.Common/PushStringInstruction.cs
@@ -0,0 +1,30 @@
+using System;
+using System.IO;
+using TLang.Common;
+
+namespace TLang.BytecodeCompiler
+{
+ public class PushStringInstruction : Instruction
+ {
+ public string Value {get;set;}
+ public PushStringInstruction(string value)
+ {
+ Value = value;
+ }
+
+ public override int CalculateLength()
+ {
+ return System.Text.Encoding.UTF8.GetByteCount(Value) + 5;
+ }
+
+ public override void WriteData(Stream strm)
+ {
+ strm.WriteByte(PUSH_STRING);
+ byte[] bytes = System.Text.Encoding.UTF8.GetBytes(Value);
+ var data=BitConverter.GetBytes(bytes.Length);
+ if(BitConverter.IsLittleEndian) Array.Reverse(data);
+ strm.Write(data,0,data.Length);
+ strm.Write(bytes,0,bytes.Length);
+ }
+ }
+}
diff --git a/TLang.Common/SimpleInstruction.cs b/TLang.Common/SimpleInstruction.cs
new file mode 100644
index 0000000..82d5330
--- /dev/null
+++ b/TLang.Common/SimpleInstruction.cs
@@ -0,0 +1,25 @@
+using System;
+using System.IO;
+using TLang.Common;
+
+namespace TLang.BytecodeCompiler
+{
+ public class SimpleInstruction : Instruction
+ {
+ public byte Value {get;set;}
+ public SimpleInstruction(byte value)
+ {
+ Value = value;
+ }
+
+ public override int CalculateLength()
+ {
+ return 1;
+ }
+
+ public override void WriteData(Stream strm)
+ {
+ strm.WriteByte(Value);
+ }
+ }
+}
diff --git a/TLang.Common/TLang.Common.csproj b/TLang.Common/TLang.Common.csproj
new file mode 100644
index 0000000..9f5c4f4
--- /dev/null
+++ b/TLang.Common/TLang.Common.csproj
@@ -0,0 +1,7 @@
+
+
+
+ netstandard2.0
+
+
+
diff --git a/TLang.Common/TLangDependency.cs b/TLang.Common/TLangDependency.cs
new file mode 100644
index 0000000..719baab
--- /dev/null
+++ b/TLang.Common/TLangDependency.cs
@@ -0,0 +1,17 @@
+namespace TLang.Common
+{
+ public class TLangDependency
+ {
+ public TLangDependency(string name,TLangVersion version)
+ {
+ Name = name;
+ Version = version;
+ }
+ public TLangDependency(string name,byte major,byte minor,byte patch,byte build) : this(name,new TLangVersion(major,minor,patch,build))
+ {
+
+ }
+ public string Name {get;set;}
+ public TLangVersion Version {get;set;}
+ }
+}
\ No newline at end of file
diff --git a/TLang.Common/TLangVersion.cs b/TLang.Common/TLangVersion.cs
new file mode 100644
index 0000000..7897f97
--- /dev/null
+++ b/TLang.Common/TLangVersion.cs
@@ -0,0 +1,54 @@
+using System;
+
+namespace TLang.Common
+{
+ public class TLangVersion
+ {
+ public static TLangVersion Version => new TLangVersion(1,0,0,0);
+
+ public int IntegerVersion => Major << 24 | Minor << 16 | Patch << 8 | Build;
+
+ public static TLangVersion FromBytes(byte[] data,int offset=0)
+ {
+ TLangVersion version=new TLangVersion();
+
+ if(offset < data.Length) version.Major = data[offset];
+ if(offset + 1 < data.Length) version.Minor = data[offset + 1];
+ if(offset + 2 < data.Length) version.Minor = data[offset + 2];
+ if(offset + 3 < data.Length) version.Minor = data[offset + 3];
+ return version;
+ }
+ public TLangVersion() : this(1,0,0,0)
+ {
+
+ }
+ public TLangVersion(byte major,byte minor,byte patch,byte build)
+ {
+ Major =major;
+ Minor = minor;
+ Patch = patch;
+ Build = build;
+ }
+ public TLangVersion(byte major,byte minor) : this(major,minor,0,0)
+ {
+
+ }
+ public static explicit operator Version(TLangVersion version)
+ {
+ return new Version(version.Major,version.Minor,version.Patch,version.Build);
+ }
+ public static explicit operator TLangVersion(Version version)
+ {
+ return new TLangVersion((byte)version.Major,(byte)version.Minor,(byte)version.Build,(byte)version.Revision);
+ }
+ public byte Major {get;set;}
+ public byte Minor {get;set;}
+
+ public byte Patch {get;set;}
+ public byte Build {get;set;}
+ public override string ToString()
+ {
+ return $"{Major}.{Minor}.{Patch}.{Build}";
+ }
+ }
+}
\ No newline at end of file
diff --git a/TLang.Lexer/LexContext.cs b/TLang.Lexer/LexContext.cs
index 7f5141d..d545f63 100644
--- a/TLang.Lexer/LexContext.cs
+++ b/TLang.Lexer/LexContext.cs
@@ -31,11 +31,7 @@ namespace TLang.Lexer
return FromOffset(Offset);
}
- public LexToken Next(int i = 0)
- {
- if(Offset + i < Tokens.Count) return Tokens[Offset + i];
- return new LexToken();
- }
+
public void Add(int i=1)
{
@@ -78,7 +74,7 @@ namespace TLang.Lexer
foreach(var item in tokenText)
{
- if(Tokens[Offset].IsDocumentation || Tokens[Offset].IsChar || Tokens[Offset].IsString || Tokens[Offset].Text == item)
+ if(!Tokens[Offset].IsDocumentation && !Tokens[Offset].IsChar && !Tokens[Offset].IsString && Tokens[Offset].Text == item)
{
token = Tokens[Offset];
if(consumeIfTrue) Offset++;
@@ -90,15 +86,15 @@ namespace TLang.Lexer
return false;
}
- public LexToken NextEntry
+ public LexToken NextEntry()
{
- get {
+
if(Offset < Tokens.Count)
{
return Tokens[Offset++];
}
return LexToken.Empty;
- }
+
}
public LexToken PeekEntry
{
diff --git a/TLang.Parser/AddNode.cs b/TLang.Parser/AddNode.cs
index 816f0f3..225653b 100644
--- a/TLang.Parser/AddNode.cs
+++ b/TLang.Parser/AddNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class AddNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public AddNode(Node left, Node right)
{
diff --git a/TLang.Parser/BAndNode.cs b/TLang.Parser/BAndNode.cs
index 8338b3f..9dcd21b 100644
--- a/TLang.Parser/BAndNode.cs
+++ b/TLang.Parser/BAndNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class BAndNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public BAndNode(Node left, Node right)
{
diff --git a/TLang.Parser/BOrNode.cs b/TLang.Parser/BOrNode.cs
index 5f571c9..18a4e37 100644
--- a/TLang.Parser/BOrNode.cs
+++ b/TLang.Parser/BOrNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class BOrNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public BOrNode(Node left, Node right)
{
diff --git a/TLang.Parser/CallNode.cs b/TLang.Parser/CallNode.cs
index 5533819..060b9fa 100644
--- a/TLang.Parser/CallNode.cs
+++ b/TLang.Parser/CallNode.cs
@@ -4,6 +4,6 @@ namespace TLang.Parser
{
public class CallNode : SymbolNode
{
- public List Arguments {get;set;}
+ public List Arguments {get;set;}=new List();
}
}
\ No newline at end of file
diff --git a/TLang.Parser/CaseNode.cs b/TLang.Parser/CaseNode.cs
index 3f017a8..a97cf45 100644
--- a/TLang.Parser/CaseNode.cs
+++ b/TLang.Parser/CaseNode.cs
@@ -5,12 +5,11 @@ namespace TLang.Parser
public class CaseNode : Node
{
public Node Variable {get;set;}
- public Node Body {get;set;}
-
- public CaseNode(Node expr, Node node)
+
+ public CaseNode(Node expr)
{
Variable = expr;
- Body = node;
+
}
diff --git a/TLang.Parser/CharNode.cs b/TLang.Parser/CharNode.cs
index d1adb69..74232a7 100644
--- a/TLang.Parser/CharNode.cs
+++ b/TLang.Parser/CharNode.cs
@@ -4,11 +4,11 @@ namespace TLang.Parser
{
public class CharNode : Node
{
- public string Text {get;set;}
+ public char Text {get;set;}
public CharNode(string text)
{
- Text = text;
+ Text = text[0];
}
diff --git a/TLang.Parser/Class1.cs b/TLang.Parser/Class1.cs
index d38bf92..3870adb 100644
--- a/TLang.Parser/Class1.cs
+++ b/TLang.Parser/Class1.cs
@@ -51,20 +51,30 @@ namespace TLang.Parser
private Node ParseNode(bool isRoot=false,bool inCase=false)
{
- ScopeNode node = new ScopeNode();
- node.LineInfo = Context.CurrentLineInfo;
-
-
- while(Context.Offset < Context.Tokens.Count && (isRoot || !Context.NextEntries(true,"}").Success))
- {
- if(Context.NextEntries(true,"{").Success)
+
+ if(Context.NextEntries(true,"{").Success || isRoot)
{
- node.Add(ParseNode());
+ ScopeNode node = new ScopeNode();
+ node.LineInfo = Context.CurrentLineInfo;
+ node.RootScope = isRoot;
+
+ while(Context.Offset < Context.Tokens.Count && !Context.Tokens[Context.Offset].IsTokenWith("}"))
+ {
+
+
+ node.Add(ParseNode());
+
+
+ if(Context.Offset < Context.Tokens.Count && Context.Tokens[Context.Offset].IsTokenWith(";")) Context.Offset++;
+ }
+ if(!isRoot)
+ Context.Offset++;
+ return node;
}
- node.Add(ParseAssigable());
- }
+ var res= ParseAssigable();
+ if(Context.MoreTokens && Context.NextEntries(true,";").Success) _=0;
- return node;
+return res;
}
private Node ParseAssigable()
@@ -233,7 +243,7 @@ namespace TLang.Parser
private Node ParseRo()
{
- Node expr = ParseRo();
+ Node expr = ParseShift();
while(Context.NextEntryIsAnyOf(true,out var token,"<","<=",">",">="))
{
@@ -332,7 +342,7 @@ namespace TLang.Parser
private Node ParseValue()
{
var doc = Context.PopDocumentation();
- var token = Context.NextEntry;
+ var token = Context.NextEntry();
if(token.IsString) return new StringNode(token.Text){LineInfo = token.Position};
if(token.IsChar) return new CharNode(token.Text){LineInfo = token.Position};
if(token.Text == "(")
@@ -345,25 +355,25 @@ namespace TLang.Parser
if(token.Text == "class")
{
ClassNode classInstance = new ClassNode();
- classInstance.Name = Context.NextEntry.Text;
+ classInstance.Name = Context.NextEntry().Text;
classInstance.Documentation = doc;
if(Context.NextEntries(true,":").Success)
{
- classInstance.InheritsFrom = Context.NextEntry.Text;
+ classInstance.InheritsFrom = Context.NextEntry().Text;
}
Context.NextEntries(true,"{");
while(Context.MoreTokens && !Context.NextEntries(true,"}").Success)
{
var doc2 = Context.PopDocumentation();
- var token2 = Context.NextEntry;
+ var token2 = Context.NextEntry();
var modifier = token2.Text;
if(Context.NextEntryIsAnyOf(true,out var token3,"func","abst"))
{
- var name = Context.NextEntry.Text;
+ var name = Context.NextEntry().Text;
if(Context.NextEntries(true,"(").Success)
{
var pos = Context.PeekEntry.Position;
@@ -374,16 +384,8 @@ namespace TLang.Parser
if(Context.Offset < Context.Tokens.Count)
{
- var n0 = ParseNode();
- var n= n0 as GetVariableNode;
- if(n != null)
- {
- args.Add(n.Name);
- }
- else
- {
- throw new CompilerError("Argument must be a GetVariableNode",n0);
- }
+ args.Add(Context.NextEntry().Text);
+
}
}
ClassEntryNode nod=new ClassEntryNode(){LineInfo = token2.Position};
@@ -399,7 +401,7 @@ namespace TLang.Parser
{
ClassEntryNode nod = new ClassEntryNode(){LineInfo = token2.Position};
nod.Documentation = doc2;
- nod.Name = Context.NextEntry.Text;
+ nod.Name = Context.NextEntry().Text;
if(!Context.NextEntries(true,"=").Success) throw new CompilerError("Invalid member",classInstance);
nod.Modifier = modifier;
@@ -426,14 +428,14 @@ namespace TLang.Parser
{
var expr = ParseNode();
if(!Context.NextEntries(true,":").Success) throw new CompilerError("Missing :",expr);
- return new CaseNode(expr,ParseNode(true,true)){LineInfo = token.Position};
+ return new CaseNode(expr){LineInfo = token.Position};
}
if(token.Text == "default")
{
var cur = Context.CurrentLineInfo;
var r=Context.NextEntries(true,":");
if(!r.Success) throw new CompilerError("Missing :",new Node(){LineInfo = cur});
- return new DefaultNode(ParseNode(true,true)){LineInfo = token.Position};
+ return new DefaultNode(){LineInfo = token.Position};
}
if(token.Text == "-")
{
@@ -451,7 +453,7 @@ namespace TLang.Parser
{
if(Context.NextEntries(true,".").Success)
{
- var entry=Context.NextEntry;
+ var entry=Context.NextEntry();
if(!entry.IsChar && !entry.IsDocumentation && !entry.IsEmpty && !entry.IsString && double.TryParse($"{number}.{entry.Text}",out var number2))
{
return new ConstNumberNode(number2);
@@ -475,16 +477,9 @@ namespace TLang.Parser
if(Context.Offset < Context.Tokens.Count)
{
- var n0 = ParseNode();
- var n= n0 as GetVariableNode;
- if(n != null)
- {
- args.Add(n.Name);
- }
- else
- {
- throw new CompilerError("Argument must be a GetVariableNode",n0);
- }
+
+ args.Add(Context.NextEntry().Text);
+
}
}
return new ClosureNode(args,ParseNode());
@@ -597,7 +592,7 @@ namespace TLang.Parser
}
while(Context.MoreTokens && Context.NextEntries(true,".").Success)
{
- var token2 = Context.NextEntry;
+ var token2 = Context.NextEntry();
if(Context.MoreTokens && Context.NextEntries(true,"(").Success)
{
@@ -641,29 +636,23 @@ namespace TLang.Parser
SymbolNode ret = new NullNode();
if(token.Text == "func")
{
- var res = new GetVariableNode(Context.NextEntry.Text);
+ var funcName= Context.NextEntry().Text;
if(Context.MoreTokens && Context.NextEntries(true,"(").Success)
{
List args=new List();
- while(!Context.NextEntries(true,")").Success)
+ while(Context.MoreTokens && !Context.NextEntries(true,")").Success)
{
if(Context.NextEntries(true,",").Success) continue;
if(Context.Offset < Context.Tokens.Count)
{
- var n0 = ParseNode();
- var n= n0 as GetVariableNode;
- if(n != null)
- {
- args.Add(n.Name);
- }
- else
- {
- throw new CompilerError("Argument must be a GetVariableNode",n0);
- }
+
+ args.Add(Context.NextEntry().Text);
+
+
}
}
- return new SetVariableNode( res,new ClosureNode(args,ParseNode()));
+ return new FunctionDeclaritionNode( funcName,new ClosureNode(args,ParseNode())){LineInfo=token.Position};
}
}
if(token.Text == "null")
@@ -695,7 +684,7 @@ namespace TLang.Parser
}
while(Context.MoreTokens && Context.NextEntries(true,".").Success)
{
- var token2 = Context.NextEntry;
+ var token2 = Context.NextEntry();
if(Context.MoreTokens && Context.NextEntries(true,"(").Success)
{
diff --git a/TLang.Parser/DefaultNode.cs b/TLang.Parser/DefaultNode.cs
index fe451bd..1ef4e63 100644
--- a/TLang.Parser/DefaultNode.cs
+++ b/TLang.Parser/DefaultNode.cs
@@ -4,11 +4,10 @@ namespace TLang.Parser
{
public class DefaultNode : Node
{
- public Node Node {get;set;}
-
- public DefaultNode(Node node)
+
+ public DefaultNode()
{
- Node = node;
+
}
diff --git a/TLang.Parser/DivideNode.cs b/TLang.Parser/DivideNode.cs
index 9cda4e2..466f478 100644
--- a/TLang.Parser/DivideNode.cs
+++ b/TLang.Parser/DivideNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class DivideNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public DivideNode(Node left, Node right)
{
diff --git a/TLang.Parser/EqualsNode.cs b/TLang.Parser/EqualsNode.cs
index 7b095d7..61f6c12 100644
--- a/TLang.Parser/EqualsNode.cs
+++ b/TLang.Parser/EqualsNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class EqualsNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public EqualsNode(Node left, Node right)
{
diff --git a/TLang.Parser/FalseNode.cs b/TLang.Parser/FalseNode.cs
new file mode 100644
index 0000000..7b681de
--- /dev/null
+++ b/TLang.Parser/FalseNode.cs
@@ -0,0 +1,6 @@
+namespace TLang.Parser
+{
+ public class FalseNode : SymbolNode
+ {
+ }
+}
\ No newline at end of file
diff --git a/TLang.Parser/FunctionDeclaritionNode.cs b/TLang.Parser/FunctionDeclaritionNode.cs
new file mode 100644
index 0000000..f81afba
--- /dev/null
+++ b/TLang.Parser/FunctionDeclaritionNode.cs
@@ -0,0 +1,18 @@
+using TLang.Lexer;
+
+namespace TLang.Parser
+{
+ public class FunctionDeclaritionNode : Node
+ {
+ public string FunctionName {get;set;}
+ public ClosureNode ClosureNode {get;set;}
+
+ public FunctionDeclaritionNode(string funcName, ClosureNode closureNode)
+ {
+ FunctionName = funcName;
+ ClosureNode = closureNode;
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/TLang.Parser/GetMemberNode.cs b/TLang.Parser/GetMemberNode.cs
index 92f4547..d83801c 100644
--- a/TLang.Parser/GetMemberNode.cs
+++ b/TLang.Parser/GetMemberNode.cs
@@ -2,11 +2,11 @@ using TLang.Lexer;
namespace TLang.Parser
{
- internal class GetMemberNode : SymbolNode
+ public class GetMemberNode : SymbolNode
{
- public SymbolNode Symbol {get;set;}
+ public Node Symbol {get;set;}
- public GetMemberNode(SymbolNode symbol, string name)
+ public GetMemberNode(Node symbol, string name)
{
Symbol = symbol;
Name = name;
diff --git a/TLang.Parser/GreaterThanEqualsNode.cs b/TLang.Parser/GreaterThanEqualsNode.cs
index b578cdd..8a1051a 100644
--- a/TLang.Parser/GreaterThanEqualsNode.cs
+++ b/TLang.Parser/GreaterThanEqualsNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class GreaterThanEqualsNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public GreaterThanEqualsNode(Node left, Node right)
{
diff --git a/TLang.Parser/GreaterThanNode.cs b/TLang.Parser/GreaterThanNode.cs
index 10ff18a..d4db651 100644
--- a/TLang.Parser/GreaterThanNode.cs
+++ b/TLang.Parser/GreaterThanNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class GreaterThanNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public GreaterThanNode(Node left, Node right)
{
diff --git a/TLang.Parser/IfNode.cs b/TLang.Parser/IfNode.cs
index 8aa1100..3dc1aee 100644
--- a/TLang.Parser/IfNode.cs
+++ b/TLang.Parser/IfNode.cs
@@ -1,6 +1,6 @@
namespace TLang.Parser
{
- internal class IfNode : Node
+ public class IfNode : Node
{
public Node Condition {get;set;}
public Node Yes {get;set;}
diff --git a/TLang.Parser/LAndNode.cs b/TLang.Parser/LAndNode.cs
index 21cc1e8..953dc58 100644
--- a/TLang.Parser/LAndNode.cs
+++ b/TLang.Parser/LAndNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class LAndNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public LAndNode(Node left, Node right)
{
diff --git a/TLang.Parser/LOrNode.cs b/TLang.Parser/LOrNode.cs
index cc8a708..f23e710 100644
--- a/TLang.Parser/LOrNode.cs
+++ b/TLang.Parser/LOrNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class LOrNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public LOrNode(Node left, Node right)
{
diff --git a/TLang.Parser/LeftShiftNode.cs b/TLang.Parser/LeftShiftNode.cs
index 034f544..ade7a7b 100644
--- a/TLang.Parser/LeftShiftNode.cs
+++ b/TLang.Parser/LeftShiftNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class LeftShiftNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public LeftShiftNode(Node left, Node right)
{
diff --git a/TLang.Parser/LessThanEqualsNode.cs b/TLang.Parser/LessThanEqualsNode.cs
index 31f5c6c..ff66163 100644
--- a/TLang.Parser/LessThanEqualsNode.cs
+++ b/TLang.Parser/LessThanEqualsNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class LessThanEqualsNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public LessThanEqualsNode(Node left, Node right)
{
diff --git a/TLang.Parser/LessThanNode.cs b/TLang.Parser/LessThanNode.cs
index 505b919..9eb0a29 100644
--- a/TLang.Parser/LessThanNode.cs
+++ b/TLang.Parser/LessThanNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class LessThanNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public LessThanNode(Node left, Node right)
{
diff --git a/TLang.Parser/ModuloNode.cs b/TLang.Parser/ModuloNode.cs
index faca061..918f61b 100644
--- a/TLang.Parser/ModuloNode.cs
+++ b/TLang.Parser/ModuloNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class ModuloNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public ModuloNode(Node left, Node right)
{
diff --git a/TLang.Parser/MultiplyNode.cs b/TLang.Parser/MultiplyNode.cs
index 54a5cc9..1f6aa19 100644
--- a/TLang.Parser/MultiplyNode.cs
+++ b/TLang.Parser/MultiplyNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class MultiplyNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public MultiplyNode(Node left, Node right)
{
diff --git a/TLang.Parser/NotEqualsNode.cs b/TLang.Parser/NotEqualsNode.cs
index 71901b9..718afc4 100644
--- a/TLang.Parser/NotEqualsNode.cs
+++ b/TLang.Parser/NotEqualsNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class NotEqualsNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public NotEqualsNode(Node left, Node right)
{
diff --git a/TLang.Parser/NullNode.cs b/TLang.Parser/NullNode.cs
new file mode 100644
index 0000000..4f61216
--- /dev/null
+++ b/TLang.Parser/NullNode.cs
@@ -0,0 +1,6 @@
+namespace TLang.Parser
+{
+ public class NullNode : SymbolNode
+ {
+ }
+}
\ No newline at end of file
diff --git a/TLang.Parser/PowNode.cs b/TLang.Parser/PowNode.cs
index a6b7568..55b245c 100644
--- a/TLang.Parser/PowNode.cs
+++ b/TLang.Parser/PowNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class PowNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public PowNode(Node left, Node right)
{
diff --git a/TLang.Parser/RightShiftNode.cs b/TLang.Parser/RightShiftNode.cs
index 8420fba..f7ecc47 100644
--- a/TLang.Parser/RightShiftNode.cs
+++ b/TLang.Parser/RightShiftNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class RightShiftNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public RightShiftNode(Node left, Node right)
{
diff --git a/TLang.Parser/ScopeNode.cs b/TLang.Parser/ScopeNode.cs
index e719f9c..d33cfa4 100644
--- a/TLang.Parser/ScopeNode.cs
+++ b/TLang.Parser/ScopeNode.cs
@@ -5,6 +5,7 @@ namespace TLang.Parser
{
public class ScopeNode : Node
{
+ public bool RootScope {get;set;}=false;
public bool IsSwitchScope {get;set;}
public Node SwitchCondition {get;set;}=new Node();
public List Nodes {get;set;}=new List();
diff --git a/TLang.Parser/SubtractNode.cs b/TLang.Parser/SubtractNode.cs
index 70b61e9..7a16a50 100644
--- a/TLang.Parser/SubtractNode.cs
+++ b/TLang.Parser/SubtractNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class SubtractNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public SubtractNode(Node left, Node right)
{
diff --git a/TLang.Parser/TrueNode.cs b/TLang.Parser/TrueNode.cs
new file mode 100644
index 0000000..6db78a7
--- /dev/null
+++ b/TLang.Parser/TrueNode.cs
@@ -0,0 +1,6 @@
+namespace TLang.Parser
+{
+ public class TrueNode : SymbolNode
+ {
+ }
+}
\ No newline at end of file
diff --git a/TLang.Parser/UndefinedNode.cs b/TLang.Parser/UndefinedNode.cs
new file mode 100644
index 0000000..b397585
--- /dev/null
+++ b/TLang.Parser/UndefinedNode.cs
@@ -0,0 +1,6 @@
+namespace TLang.Parser
+{
+ public class UndefinedNode : SymbolNode
+ {
+ }
+}
\ No newline at end of file
diff --git a/TLang.Parser/XOrNode.cs b/TLang.Parser/XOrNode.cs
index c36f24f..f05a230 100644
--- a/TLang.Parser/XOrNode.cs
+++ b/TLang.Parser/XOrNode.cs
@@ -2,8 +2,8 @@ namespace TLang.Parser
{
public class XOrNode : Node
{
- private Node Left {get;set;}
- private Node Right {get;set;}
+ public Node Left {get;set;}
+ public Node Right {get;set;}
public XOrNode(Node left, Node right)
{
diff --git a/TLang.VM/Chunk.cs b/TLang.VM/Chunk.cs
new file mode 100644
index 0000000..2814c5d
--- /dev/null
+++ b/TLang.VM/Chunk.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace TLang.VM
+{
+ public class Chunk
+ {
+ public List Arguments {get;set;}=new List();
+
+ public byte[] Code {get;set;}
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/ChunkExecuter.cs b/TLang.VM/ChunkExecuter.cs
new file mode 100644
index 0000000..b86d7fd
--- /dev/null
+++ b/TLang.VM/ChunkExecuter.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections.Generic;
+using TLang.BytecodeCompiler;
+using TLang.Common;
+namespace TLang.VM
+{
+ public class ChunkExecuter
+ {
+ public string ClassName {get;set;}="";
+ public ChunkExecuter(TVMFile file,Chunk chunk,TLangEnvironment env)
+ {
+ File =file;
+ Chunk = chunk;
+ Environment = env;
+ }
+ public TLangEnvironment Environment {get;set;}
+ public TVMFile File {get;}
+
+ public Chunk Chunk {get;}
+ public int IP {get;set;}=0;
+ public Stack Stack {get;}=new Stack();
+
+
+ public TObject Execute(params TObject[] args)
+ {
+ var env=Environment.GetSubEnvironment();
+ for(int i = 0;i< args.Length;i++)
+ {
+ if(i= File.Chunks.Count) throw new IndexOutOfRangeException($"No chunk with id {closureId}");
+ Stack.Push(new TClosure(File,File.Chunks[closureId],env));
+ break;
+ case Instruction.PUSH_STRING:
+ Stack.Push(new TString(ReadString()));
+ break;
+ case Instruction.PUSH_VARIABLE_VALUE:
+ {
+ var res=EnsurePop();
+ Stack.Push(env.GetObject(res.Value));
+ }
+ break;
+ case Instruction.POP_VARIABLE_VALUE:
+ {
+ var res=EnsurePop();
+ env.SetObject(res.Value,Stack.Pop());
+ }
+ break;
+ case Instruction.CALL_FUNC:
+ {
+ var argC = (int)EnsurePop().Value;
+ TObject[] argV = new TObject[argC];
+ for(int i = argC;i>0;i--)
+ {
+ argV[i] = Stack.Pop();
+ }
+ var name = EnsurePop();
+ var callable=env.GetObject(name.Value) as TCallable;
+ if(callable != null)
+ {
+ Stack.Push(callable.Execute(argV));
+ }else{
+ Stack.Push(new TUndefined());
+ }
+ }
+ break;
+ case Instruction.CALL_METHOD:
+ {
+ var argC = (int)EnsurePop().Value;
+ TObject[] argV = new TObject[argC];
+ for(int i = argC;i>0;i--)
+ {
+ argV[i] = Stack.Pop();
+ }
+ var name = EnsurePop();
+ var symbol = Stack.Pop();
+
+ Stack.Push(ExecuteMethod(symbol,name.Value,argV));
+ }
+ break;
+ }
+ }
+ if(Stack.Count > 0)
+ return Stack.Pop();
+ return new TNull();
+ }
+
+ private TObject ExecuteMethod(TObject symbol, string name, params TObject[] argV)
+ {
+
+ }
+
+ private T EnsurePop() where T : TObject
+ {
+ var item = Stack.Pop() as T;
+ if(item == null) throw new Exception("Pop failed");
+ return item;
+ }
+
+ private double ReadDouble()
+ {
+ if(IP + 8 < Chunk.Code.Length)
+ {
+ byte[] data =new byte[8];
+ Array.Copy(Chunk.Code,IP,data,0,8);
+ IP += 8;
+ if(BitConverter.IsLittleEndian) Array.Reverse(data);
+ return BitConverter.ToDouble(data,0);
+ }
+ throw new Exception("Malformed binary");
+ }
+ private int ReadInt()
+ {
+ if(IP + 4 < Chunk.Code.Length)
+ {
+ byte[] data =new byte[4];
+ Array.Copy(Chunk.Code,IP,data,0,4);
+ IP += 4;
+ if(BitConverter.IsLittleEndian) Array.Reverse(data);
+ return BitConverter.ToInt32(data,0);
+ }
+ throw new Exception("Malformed binary");
+ }
+ private string ReadString()
+ {
+ int strLen = ReadInt();
+ if(IP + strLen < Chunk.Code.Length)
+ {
+ var str=System.Text.Encoding.UTF8.GetString(Chunk.Code,IP,strLen);
+ IP += strLen;
+ return str;
+ }
+ throw new Exception("Malformed binary");
+ }
+ private TObject Mod(TObject object1, TObject object2)
+ {
+ throw new NotImplementedException();
+ }
+
+ private TObject Divide(TObject object1, TObject object2)
+ {
+ throw new NotImplementedException();
+ }
+
+ private TObject Times(TObject object1, TObject object2)
+ {
+ throw new NotImplementedException();
+ }
+
+ private TObject Sub(TObject object2, TObject object1)
+ {
+ throw new NotImplementedException();
+ }
+
+ private TObject Add(TObject object2, TObject object1)
+ {
+ var left = object2 as TNumber;
+ var right = object1 as TNumber;
+ var lStr = object2 as TString;
+ var rStr = object1 as TString;
+ if(left != null && right != null)
+ {
+ return new TNumber(left.Value + right.Value);
+ }
+ if(lStr != null && rStr != null)
+ {
+ return new TString(lStr.Value + rStr.Value);
+ }
+ return new TNumber(0);
+ }
+ }
+
+
+}
diff --git a/TLang.VM/Class.cs b/TLang.VM/Class.cs
new file mode 100644
index 0000000..2e266e0
--- /dev/null
+++ b/TLang.VM/Class.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+
+namespace TLang.VM
+{
+ public class Class
+ {
+ public string Name {get;set;}="";
+ public string InheritsFrom {get;set;}="";
+
+ public List ClassEntries {get;set;}=new List();
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/ClassEntry.cs b/TLang.VM/ClassEntry.cs
new file mode 100644
index 0000000..b6a28bd
--- /dev/null
+++ b/TLang.VM/ClassEntry.cs
@@ -0,0 +1,18 @@
+namespace TLang.VM
+{
+ public class ClassEntry
+ {
+ public byte Modifier {get;set;}=0;
+ public bool Abstract => (Modifier & 0b00001000) > 0;
+
+ public bool Method => (Modifier & 0b00000100) > 0;
+
+ public bool Private => (Modifier & 0b00000011) == 0;
+ public bool Protected => (Modifier & 0b00000011) == 1;
+ public bool Public => (Modifier & 0b00000011) == 2;
+
+ public string Name {get;set;}
+
+ public int ChunkId {get;set;}
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/ClassEnvironment.cs b/TLang.VM/ClassEnvironment.cs
new file mode 100644
index 0000000..fba324d
--- /dev/null
+++ b/TLang.VM/ClassEnvironment.cs
@@ -0,0 +1,49 @@
+namespace TLang.VM
+{
+ internal class ClassEnvironment : TLangEnvironment
+ {
+ private TLangEnvironment oGenv;
+ private TClassInstance classInstance;
+
+ public ClassEnvironment(TLangEnvironment oGenv, TClassInstance classInstance)
+ {
+ this.oGenv = oGenv;
+ this.classInstance = classInstance;
+ }
+
+ public override TObject GetObject(string key)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override TLangEnvironment GetParentEnvironment()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override RootEnvironment GetRootEnvironment()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override TLangEnvironment GetSubEnvironment()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override bool HasObject(string key)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override bool HasObjectRecurse(string key)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public override void SetObject(string key, TObject value)
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/ClassMethod.cs b/TLang.VM/ClassMethod.cs
new file mode 100644
index 0000000..f757777
--- /dev/null
+++ b/TLang.VM/ClassMethod.cs
@@ -0,0 +1,15 @@
+namespace TLang.VM
+{
+ public class ClassMethod
+ {
+ public bool Public {get;set;}
+
+ public bool Private {get;set;}
+
+ public bool Protected {get;set;}
+
+ public Chunk Chunk {get;set;}
+
+ public TVMFile File {get;set;}
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/DefaultDependencyPool.cs b/TLang.VM/DefaultDependencyPool.cs
new file mode 100644
index 0000000..45d7132
--- /dev/null
+++ b/TLang.VM/DefaultDependencyPool.cs
@@ -0,0 +1,50 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using TLang.Common;
+
+namespace TLang.VM
+{
+ public class DefaultDependencyPool : IDependencyPool
+ {
+ List<(TLangDependency Dependency,TVMFile File)> items = new List<(TLangDependency Dependency, TVMFile File)>();
+ public bool AddDependency(TLangDependency dependency)
+ {
+ string fileName = $"{dependency.Name}-{dependency.Version}.tvm";
+ if(File.Exists(fileName))
+ {
+ using(var f = File.OpenRead(fileName))
+ {
+ TVMFile file = new TVMFile(f);
+ items.Add((dependency,file));
+ return file.LoadDependencies(this);
+ }
+ }
+ return false;
+ }
+ private static TLangDependencyResponse DefaultDependencyCheck(TLangDependency dep)
+ {
+ string fileName = $"{dep.Name}-{dep.Version}.tvm";
+ if(File.Exists(fileName))
+ {
+ return new TLangDependencyResponse(){Stream = File.OpenRead(fileName)};
+ }
+ return new TLangDependencyResponse(){Found = false};
+ }
+
+ public bool DependencyExists(TLangDependency dependency)
+ {
+ throw new System.NotImplementedException();
+ }
+
+ public IEnumerator<(TLangDependency Dependency, TVMFile File)> GetEnumerator()
+ {
+ throw new System.NotImplementedException();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ throw new System.NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/Function.cs b/TLang.VM/Function.cs
new file mode 100644
index 0000000..14ef599
--- /dev/null
+++ b/TLang.VM/Function.cs
@@ -0,0 +1,8 @@
+namespace TLang.VM
+{
+ public class Function
+ {
+ public string Name {get;set;}
+ public int ChunkId {get;set;}
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/IDependencyPool.cs b/TLang.VM/IDependencyPool.cs
new file mode 100644
index 0000000..8496ff6
--- /dev/null
+++ b/TLang.VM/IDependencyPool.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+using TLang.Common;
+
+namespace TLang.VM
+{
+ public interface IDependencyPool : IEnumerable<(TLangDependency Dependency,TVMFile File)>
+ {
+
+
+ bool DependencyExists(TLangDependency dependency);
+
+ bool AddDependency(TLangDependency dependency,RootEnvironment env);
+
+
+
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/LoadedClassData.cs b/TLang.VM/LoadedClassData.cs
new file mode 100644
index 0000000..700ee77
--- /dev/null
+++ b/TLang.VM/LoadedClassData.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+
+namespace TLang.VM
+{
+ public class LoadedClassData
+ {
+ public LoadedClassData(string inheritsFrom,TVMFile file,List entries)
+ {
+ InheritsFrom = inheritsFrom;
+ File = file;
+ Entries = entries;
+ }
+ public string InheritsFrom {get;set;}
+
+ public TVMFile File {get;set;}
+
+ public List Entries {get;set;}
+
+ internal Class ToClass(string name)
+ {
+ Class cla=new Class();
+ cla.ClassEntries = Entries;
+ cla.InheritsFrom = InheritsFrom;
+ cla.Name = name;
+ return cla;
+ }
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/RootEnvironment.cs b/TLang.VM/RootEnvironment.cs
new file mode 100644
index 0000000..046b3fe
--- /dev/null
+++ b/TLang.VM/RootEnvironment.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+
+namespace TLang.VM
+{
+ public class RootEnvironment : TLangEnvironment
+ {
+ public RootEnvironment()
+ {
+
+ }
+ public Dictionary AvailableClasses {get;set;}=new Dictionary();
+
+ Dictionary items = new Dictionary();
+ public override TObject GetObject(string key)
+ {
+ if(HasObject(key))
+ {
+ return items[key];
+ }
+ return new TUndefined();
+ }
+
+ public override bool HasObject(string key)
+ {
+ return items.ContainsKey(key);
+ }
+
+ public override TLangEnvironment GetParentEnvironment()
+ {
+ return this;
+ }
+
+ public override RootEnvironment GetRootEnvironment()
+ {
+ return this;
+ }
+
+ public override void SetObject(string key, TObject value)
+ {
+ items[key] = value;
+ }
+ public override bool HasObjectRecurse(string key)
+ {
+ return HasObject(key);
+ }
+ public override TLangEnvironment GetSubEnvironment()
+ {
+ return new SubEnvironment(this);
+ }
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/SubEnvironment.cs b/TLang.VM/SubEnvironment.cs
new file mode 100644
index 0000000..731d661
--- /dev/null
+++ b/TLang.VM/SubEnvironment.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+
+namespace TLang.VM
+{
+ public class SubEnvironment : TLangEnvironment
+ {
+ public SubEnvironment(TLangEnvironment env)
+ {
+ this.pEnv=env;
+ }
+ TLangEnvironment pEnv;
+
+ Dictionary items = new Dictionary();
+ public override TObject GetObject(string key)
+ {
+ if(pEnv.HasObjectRecurse(key))
+ {
+ return pEnv.GetObject(key);
+ }
+ if(HasObject(key))
+ {
+ return items[key];
+ }
+ return new TUndefined();
+ }
+
+ public override bool HasObject(string key)
+ {
+ return items.ContainsKey(key);
+ }
+ public override bool HasObjectRecurse(string key)
+ {
+ return HasObject(key) && pEnv.HasObjectRecurse(key);
+ }
+
+
+ public override TLangEnvironment GetParentEnvironment()
+ {
+ return pEnv;
+ }
+
+ public override RootEnvironment GetRootEnvironment()
+ {
+ return pEnv.GetRootEnvironment();
+ }
+
+ public override void SetObject(string key, TObject value)
+ {
+ if(pEnv.HasObjectRecurse(key))
+ {
+ pEnv.SetObject(key,value);
+ }
+ else
+ {
+ items[key] = value;
+ }
+
+ }
+
+ public override TLangEnvironment GetSubEnvironment()
+ {
+ return new SubEnvironment(this);
+ }
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/TCallable.cs b/TLang.VM/TCallable.cs
new file mode 100644
index 0000000..75f3892
--- /dev/null
+++ b/TLang.VM/TCallable.cs
@@ -0,0 +1,7 @@
+namespace TLang.VM
+{
+ public abstract class TCallable : TObject
+ {
+ public abstract TObject Execute(params TObject[] args);
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/TClassInstance.cs b/TLang.VM/TClassInstance.cs
new file mode 100644
index 0000000..8a26bb6
--- /dev/null
+++ b/TLang.VM/TClassInstance.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+
+namespace TLang.VM
+{
+ public class TClassInstance : TObject
+ {
+ TVMFile file;
+ Class classEntry;
+ TLangEnvironment oGenv;
+ public TClassInstance(TVMFile file,Class classEntry,TLangEnvironment env)
+ {
+ this.file = file;
+ this.classEntry = classEntry;
+ this.oGenv = env;
+ }
+ public List InheritenceTree {get;}=new List();
+ public Dictionary Methods {get;} = new Dictionary();
+
+
+
+ public void Init(params TObject[] args)
+ {
+ Environment = new ClassEnvironment(oGenv,this);
+
+ foreach(var item in classEntry.ClassEntries)
+ {
+
+ }
+ var cE = classEntry;
+ var aC =oGenv.GetRootEnvironment().AvailableClasses;
+ //we need to check inheritence
+ while(cE.InheritsFrom != "object")
+ {
+ InheritenceTree.Add(cE.InheritsFrom);
+ if(aC.ContainsKey(cE.InheritsFrom))
+ {
+ var aC2 = aC[cE.InheritsFrom];
+ cE = aC2.ToClass(cE.InheritsFrom);
+ foreach(var item in cE.ClassEntries)
+ {
+ if(!Methods.ContainsKey(item.Name) && item.Method)
+ {
+ if(item.Abstract) throw new Exception("Method is abstract");
+ ClassMethod meth=new ClassMethod();
+ meth.File = aC2.File;
+ meth.Chunk = aC2.File.Chunks[item.ChunkId];
+ meth.Private = item.Private;
+ meth.Protected = item.Protected;
+ meth.Public = item.Public;
+ Methods.Add(item.Name,meth);
+ }
+ }
+ }
+ }
+ }
+ public TLangEnvironment Environment {get; private set;}
+ public void SetField(bool inside,string className,string key,TObject obj)
+ {
+
+ }
+ public TObject GetField(string className,string key)
+ {
+
+ return new TUndefined();
+ }
+ public TObject CallMethod(string className,string key,params TObject[] args)
+ {
+ if(Methods.ContainsKey(key))
+ {
+ var method=Methods[key];
+ if(method.Private && className != classEntry.Name) return new TUndefined();
+
+ }
+
+ return new TUndefined();
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/TClosure.cs b/TLang.VM/TClosure.cs
new file mode 100644
index 0000000..3b65328
--- /dev/null
+++ b/TLang.VM/TClosure.cs
@@ -0,0 +1,22 @@
+namespace TLang.VM
+{
+ public class TClosure : TCallable
+ {
+ private TVMFile file;
+ private Chunk chunk;
+ private TLangEnvironment env;
+
+ public TClosure(TVMFile file, Chunk chunk, TLangEnvironment env)
+ {
+ this.file = file;
+ this.chunk = chunk;
+ this.env = env;
+ }
+
+ public override TObject Execute(params TObject[] args)
+ {
+ ChunkExecuter executer = new ChunkExecuter(file,chunk,env);
+ return executer.Execute(args);
+ }
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/TLang.VM.csproj b/TLang.VM/TLang.VM.csproj
new file mode 100644
index 0000000..a1c6194
--- /dev/null
+++ b/TLang.VM/TLang.VM.csproj
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+ netstandard2.0
+
+
+
diff --git a/TLang.VM/TLangDependencyResponse.cs b/TLang.VM/TLangDependencyResponse.cs
new file mode 100644
index 0000000..50b5e4b
--- /dev/null
+++ b/TLang.VM/TLangDependencyResponse.cs
@@ -0,0 +1,15 @@
+using System.IO;
+
+namespace TLang.VM
+{
+ public class TLangDependencyResponse
+ {
+ public bool IgnoreVersion {get;set;}=false;
+
+ public Stream Stream {get;set;}=Stream.Null;
+
+ public bool DisposeStream {get;set;}=true;
+
+ public bool Found {get;set;}=false;
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/TLangEnvironment.cs b/TLang.VM/TLangEnvironment.cs
new file mode 100644
index 0000000..b163743
--- /dev/null
+++ b/TLang.VM/TLangEnvironment.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace TLang.VM
+{
+ public abstract class TLangEnvironment
+ {
+ public abstract TLangEnvironment GetSubEnvironment();
+
+ public abstract TObject GetObject(string key);
+
+ public abstract void SetObject(string key,TObject value);
+
+ public abstract bool HasObject(string key);
+
+ public abstract bool HasObjectRecurse(string key);
+
+ public abstract RootEnvironment GetRootEnvironment();
+
+ public abstract TLangEnvironment GetParentEnvironment();
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/TNull.cs b/TLang.VM/TNull.cs
new file mode 100644
index 0000000..fffed42
--- /dev/null
+++ b/TLang.VM/TNull.cs
@@ -0,0 +1,6 @@
+namespace TLang.VM
+{
+ public class TNull : TObject
+ {
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/TNumber.cs b/TLang.VM/TNumber.cs
new file mode 100644
index 0000000..144ab55
--- /dev/null
+++ b/TLang.VM/TNumber.cs
@@ -0,0 +1,12 @@
+namespace TLang.VM
+{
+ public class TNumber : TObject
+ {
+ public double Value {get;set;}
+
+ public TNumber(double value)
+ {
+ this.Value = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/TObject.cs b/TLang.VM/TObject.cs
new file mode 100644
index 0000000..7819649
--- /dev/null
+++ b/TLang.VM/TObject.cs
@@ -0,0 +1,6 @@
+namespace TLang.VM
+{
+ public class TObject
+ {
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/TString.cs b/TLang.VM/TString.cs
new file mode 100644
index 0000000..c4bc272
--- /dev/null
+++ b/TLang.VM/TString.cs
@@ -0,0 +1,12 @@
+namespace TLang.VM
+{
+ public class TString : TObject
+ {
+ public string Value {get;set;}
+
+ public TString(string value)
+ {
+ this.Value = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/TUndefined.cs b/TLang.VM/TUndefined.cs
new file mode 100644
index 0000000..fecdb48
--- /dev/null
+++ b/TLang.VM/TUndefined.cs
@@ -0,0 +1,6 @@
+namespace TLang.VM
+{
+ public class TUndefined : TObject
+ {
+ }
+}
\ No newline at end of file
diff --git a/TLang.VM/TVMFile.cs b/TLang.VM/TVMFile.cs
new file mode 100644
index 0000000..849dc84
--- /dev/null
+++ b/TLang.VM/TVMFile.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using TLang.Common;
+
+namespace TLang.VM
+{
+ public class TVMFile
+ {
+ public List Classes {get;set;}=new List();
+ public List Functions {get;set;}=new List();
+ public List Dependencies {get;set;}=new List();
+
+ public List Chunks {get;set;}=new List();
+ public TLangVersion Version {get;set;}
+ public RootEnvironment Environment {get;private set;}
+ public TVMFile(Stream file,RootEnvironment env)
+ {
+ Environment = env;
+ byte[] data=new byte[11];
+ int read=file.Read(data,0,data.Length);
+ CheckData(data,read);
+ int deps=ReadBigEndianIntenger(file);
+ for(int i = 0;i 0)
+ read0=file.Read(code,offset,read0);
+
+ offset+=read0;
+ } while(read0 > 0);
+ chunk.Code = code;
+ Chunks.Add(chunk);
+ }
+ }
+ private void EnsureRead(Stream file,byte[] data)
+ {
+ int i = file.Read(data,0,data.Length);
+ if(i != data.Length) throw new IndexOutOfRangeException("Array must be filled");
+
+ }
+ private int ReadBigEndianIntenger(Stream file)
+ {
+ byte[] bytes=new byte[4];
+ EnsureRead(file,bytes);
+ if(BitConverter.IsLittleEndian) Array.Reverse(bytes);
+ return BitConverter.ToInt32(bytes,0);
+ }
+
+ private void CheckData(byte[] data, int read)
+ {
+ if(read < 11 || data[0] != 'T' || data[1] != 'V' || data[2] != 'M') throw new BadImageFormatException("TVM file invalid");
+
+ if(TLangVersion.FromBytes(data,3).IntegerVersion > TLangVersion.Version.IntegerVersion) throw new BadImageFormatException("TVM Version is too old");
+
+ Version = TLangVersion.FromBytes(data,7);
+
+ }
+
+ public bool LoadDependencies(IDependencyPool dependencyPool)
+ {
+ foreach(var dep in Dependencies)
+ {
+ if(!dependencyPool.DependencyExists(dep))
+ {
+ if(!dependencyPool.AddDependency(dep,Environment)) return false;
+ }
+ }
+ foreach(var func in Functions)
+ {
+ Environment.SetObject(func.Name,new TClosure(this,Chunks[func.ChunkId],Environment));
+ }
+ foreach(var class0 in Classes)
+ {
+ Environment.AvailableClasses.Add(class0.Name,new LoadedClassData(class0.InheritsFrom,this,class0.ClassEntries));
+ }
+ return true;
+
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/VMTest/.vscode/launch.json b/VMTest/.vscode/launch.json
new file mode 100644
index 0000000..0b14c26
--- /dev/null
+++ b/VMTest/.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/dotnet/vscode-csharp/blob/main/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/net7.0/VMTest.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/VMTest/.vscode/tasks.json b/VMTest/.vscode/tasks.json
new file mode 100644
index 0000000..4625b9e
--- /dev/null
+++ b/VMTest/.vscode/tasks.json
@@ -0,0 +1,41 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/VMTest.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/VMTest.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "--project",
+ "${workspaceFolder}/VMTest.csproj"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/VMTest/Program.cs b/VMTest/Program.cs
new file mode 100644
index 0000000..e7b795e
--- /dev/null
+++ b/VMTest/Program.cs
@@ -0,0 +1,10 @@
+using TLang.VM;
+using var f = File.OpenRead("app.tvm");
+TVMFile file = new TVMFile(f);
+
+ChunkExecuter executer=new ChunkExecuter(file,file.Chunks[0],new RootEnvironment());
+var res=executer.Execute() as TNumber;
+if(res != null)
+{
+ Console.WriteLine($"Number: {res.Value}");
+}
\ No newline at end of file
diff --git a/VMTest/VMTest.csproj b/VMTest/VMTest.csproj
new file mode 100644
index 0000000..a07b8b7
--- /dev/null
+++ b/VMTest/VMTest.csproj
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
diff --git a/VMTest/app.tvm b/VMTest/app.tvm
new file mode 100644
index 0000000..3817887
Binary files /dev/null and b/VMTest/app.tvm differ