Working on VM
This commit is contained in:
parent
c48bd44bc3
commit
461b439d5b
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\TLang.BytecodeCompiler\TLang.BytecodeCompiler.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -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));
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
37+5;
|
Binary file not shown.
|
@ -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<ClassNode> Classes {get;set;}=new List<ClassNode>();
|
||||
public List<FunctionDeclaritionNode> Functions {get;set;}=new List<FunctionDeclaritionNode>();
|
||||
public BytecodeChunk RootChunk = new BytecodeChunk();
|
||||
public List<BytecodeChunk> Chunks {get;set;}=new List<BytecodeChunk>();
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\TLang.Parser\TLang.Parser.csproj" />
|
||||
<ProjectReference Include="..\TLang.Common\TLang.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -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<string,int> Offsets {get;set;}=new Dictionary<string, int>();
|
||||
public List<string> Arguments {get;set;}=new List<string>();
|
||||
public List<Instruction> Instructions {get;set;}=new List<Instruction>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace TLang.Common
|
||||
{
|
||||
public interface ILabelable
|
||||
{
|
||||
string Key {get;set;}
|
||||
int Value {get;set;}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -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;}
|
||||
}
|
||||
}
|
|
@ -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}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -4,6 +4,6 @@ namespace TLang.Parser
|
|||
{
|
||||
public class CallNode : SymbolNode
|
||||
{
|
||||
public List<Node> Arguments {get;set;}
|
||||
public List<Node> Arguments {get;set;}=new List<Node>();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
node.Add(ParseAssigable());
|
||||
}
|
||||
ScopeNode node = new ScopeNode();
|
||||
node.LineInfo = Context.CurrentLineInfo;
|
||||
node.RootScope = isRoot;
|
||||
|
||||
return node;
|
||||
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;
|
||||
}
|
||||
var res= ParseAssigable();
|
||||
if(Context.MoreTokens && Context.NextEntries(true,";").Success) _=0;
|
||||
|
||||
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<string> args=new List<string>();
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -4,11 +4,10 @@ namespace TLang.Parser
|
|||
{
|
||||
public class DefaultNode : Node
|
||||
{
|
||||
public Node Node {get;set;}
|
||||
|
||||
public DefaultNode(Node node)
|
||||
public DefaultNode()
|
||||
{
|
||||
Node = node;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
namespace TLang.Parser
|
||||
{
|
||||
public class FalseNode : SymbolNode
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
namespace TLang.Parser
|
||||
{
|
||||
public class NullNode : SymbolNode
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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<Node> Nodes {get;set;}=new List<Node>();
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
namespace TLang.Parser
|
||||
{
|
||||
public class TrueNode : SymbolNode
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
namespace TLang.Parser
|
||||
{
|
||||
public class UndefinedNode : SymbolNode
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace TLang.VM
|
||||
{
|
||||
public class Chunk
|
||||
{
|
||||
public List<string> Arguments {get;set;}=new List<string>();
|
||||
|
||||
public byte[] Code {get;set;}
|
||||
}
|
||||
}
|
|
@ -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<TObject> Stack {get;}=new Stack<TObject>();
|
||||
|
||||
|
||||
public TObject Execute(params TObject[] args)
|
||||
{
|
||||
var env=Environment.GetSubEnvironment();
|
||||
for(int i = 0;i< args.Length;i++)
|
||||
{
|
||||
if(i<Chunk.Arguments.Count)
|
||||
{
|
||||
env.SetObject(Chunk.Arguments[i],args[i]);
|
||||
}
|
||||
}
|
||||
while(IP < Chunk.Code.Length)
|
||||
{
|
||||
var instruction = Chunk.Code[IP++];
|
||||
switch(instruction)
|
||||
{
|
||||
case Instruction.ADD:
|
||||
Stack.Push(Add(Stack.Pop(),Stack.Pop()));
|
||||
break;
|
||||
case Instruction.SUB:
|
||||
Stack.Push(Sub(Stack.Pop(),Stack.Pop()));
|
||||
break;
|
||||
case Instruction.TIMES:
|
||||
Stack.Push(Times(Stack.Pop(),Stack.Pop()));
|
||||
break;
|
||||
case Instruction.DIVIDE:
|
||||
Stack.Push(Divide(Stack.Pop(),Stack.Pop()));
|
||||
break;
|
||||
case Instruction.MOD:
|
||||
Stack.Push(Mod(Stack.Pop(),Stack.Pop()));
|
||||
break;
|
||||
case Instruction.RET:
|
||||
return Stack.Pop();
|
||||
|
||||
case Instruction.SCOPE_BEGIN:
|
||||
env = Environment.GetSubEnvironment();
|
||||
break;
|
||||
case Instruction.SCOPE_END:
|
||||
env = Environment.GetParentEnvironment();
|
||||
break;
|
||||
case Instruction.PUSH_DOUBLE:
|
||||
Stack.Push(new TNumber(ReadDouble()));
|
||||
break;
|
||||
case Instruction.PUSH_CLOSURE:
|
||||
int closureId = ReadInt();
|
||||
if(closureId >= 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<TString>();
|
||||
Stack.Push(env.GetObject(res.Value));
|
||||
}
|
||||
break;
|
||||
case Instruction.POP_VARIABLE_VALUE:
|
||||
{
|
||||
var res=EnsurePop<TString>();
|
||||
env.SetObject(res.Value,Stack.Pop());
|
||||
}
|
||||
break;
|
||||
case Instruction.CALL_FUNC:
|
||||
{
|
||||
var argC = (int)EnsurePop<TNumber>().Value;
|
||||
TObject[] argV = new TObject[argC];
|
||||
for(int i = argC;i>0;i--)
|
||||
{
|
||||
argV[i] = Stack.Pop();
|
||||
}
|
||||
var name = EnsurePop<TString>();
|
||||
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<TNumber>().Value;
|
||||
TObject[] argV = new TObject[argC];
|
||||
for(int i = argC;i>0;i--)
|
||||
{
|
||||
argV[i] = Stack.Pop();
|
||||
}
|
||||
var name = EnsurePop<TString>();
|
||||
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<T>() 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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<ClassEntry> ClassEntries {get;set;}=new List<ClassEntry>();
|
||||
}
|
||||
}
|
|
@ -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;}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
namespace TLang.VM
|
||||
{
|
||||
public class Function
|
||||
{
|
||||
public string Name {get;set;}
|
||||
public int ChunkId {get;set;}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TLang.VM
|
||||
{
|
||||
public class LoadedClassData
|
||||
{
|
||||
public LoadedClassData(string inheritsFrom,TVMFile file,List<ClassEntry> entries)
|
||||
{
|
||||
InheritsFrom = inheritsFrom;
|
||||
File = file;
|
||||
Entries = entries;
|
||||
}
|
||||
public string InheritsFrom {get;set;}
|
||||
|
||||
public TVMFile File {get;set;}
|
||||
|
||||
public List<ClassEntry> Entries {get;set;}
|
||||
|
||||
internal Class ToClass(string name)
|
||||
{
|
||||
Class cla=new Class();
|
||||
cla.ClassEntries = Entries;
|
||||
cla.InheritsFrom = InheritsFrom;
|
||||
cla.Name = name;
|
||||
return cla;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace TLang.VM
|
||||
{
|
||||
public class RootEnvironment : TLangEnvironment
|
||||
{
|
||||
public RootEnvironment()
|
||||
{
|
||||
|
||||
}
|
||||
public Dictionary<string, LoadedClassData> AvailableClasses {get;set;}=new Dictionary<string, LoadedClassData>();
|
||||
|
||||
Dictionary<string,TObject> items = new Dictionary<string, TObject>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<string,TObject> items = new Dictionary<string, TObject>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
namespace TLang.VM
|
||||
{
|
||||
public abstract class TCallable : TObject
|
||||
{
|
||||
public abstract TObject Execute(params TObject[] args);
|
||||
}
|
||||
}
|
|
@ -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<string> InheritenceTree {get;}=new List<string>();
|
||||
public Dictionary<string,ClassMethod> Methods {get;} = new Dictionary<string, ClassMethod>();
|
||||
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\TLang.Common\TLang.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
namespace TLang.VM
|
||||
{
|
||||
public class TNull : TObject
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
namespace TLang.VM
|
||||
{
|
||||
public class TNumber : TObject
|
||||
{
|
||||
public double Value {get;set;}
|
||||
|
||||
public TNumber(double value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
namespace TLang.VM
|
||||
{
|
||||
public class TObject
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
namespace TLang.VM
|
||||
{
|
||||
public class TString : TObject
|
||||
{
|
||||
public string Value {get;set;}
|
||||
|
||||
public TString(string value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
namespace TLang.VM
|
||||
{
|
||||
public class TUndefined : TObject
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using TLang.Common;
|
||||
|
||||
namespace TLang.VM
|
||||
{
|
||||
public class TVMFile
|
||||
{
|
||||
public List<Class> Classes {get;set;}=new List<Class>();
|
||||
public List<Function> Functions {get;set;}=new List<Function>();
|
||||
public List<TLangDependency> Dependencies {get;set;}=new List<TLangDependency>();
|
||||
|
||||
public List<Chunk> Chunks {get;set;}=new List<Chunk>();
|
||||
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<deps;i++)
|
||||
{
|
||||
int nameLen = ReadBigEndianIntenger(file);
|
||||
data = new byte[nameLen];
|
||||
EnsureRead(file,data);
|
||||
string name = System.Text.Encoding.UTF8.GetString(data);
|
||||
data = new byte[4];
|
||||
EnsureRead(file,data);
|
||||
var version = TLangVersion.FromBytes(data,0);
|
||||
Dependencies.Add(new TLangDependency(name,version));
|
||||
}
|
||||
int funcsLen = ReadBigEndianIntenger(file);
|
||||
for(int i = 0;i<funcsLen;i++)
|
||||
{
|
||||
int nameLen = ReadBigEndianIntenger(file);
|
||||
data = new byte[nameLen];
|
||||
EnsureRead(file,data);
|
||||
string name = System.Text.Encoding.UTF8.GetString(data);
|
||||
int chunkId = ReadBigEndianIntenger(file);
|
||||
Functions.Add(new Function(){Name = name,ChunkId = chunkId});
|
||||
}
|
||||
int classLen = ReadBigEndianIntenger(file);
|
||||
for(int i = 0;i<classLen;i++)
|
||||
{
|
||||
int nameLen = ReadBigEndianIntenger(file);
|
||||
data = new byte[nameLen];
|
||||
EnsureRead(file,data);
|
||||
string name = System.Text.Encoding.UTF8.GetString(data);
|
||||
nameLen = ReadBigEndianIntenger(file);
|
||||
data = new byte[nameLen];
|
||||
EnsureRead(file,data);
|
||||
string inheritsFrom = System.Text.Encoding.UTF8.GetString(data);
|
||||
Class classes = new Class();
|
||||
classes.Name = name;
|
||||
classes.InheritsFrom = inheritsFrom;
|
||||
|
||||
int classEntryCount = ReadBigEndianIntenger(file);
|
||||
for(int j = 0;j<classEntryCount;j++)
|
||||
{
|
||||
int modifier = file.ReadByte();
|
||||
if(modifier == -1) throw new IOException("End of file");
|
||||
nameLen = ReadBigEndianIntenger(file);
|
||||
data = new byte[nameLen];
|
||||
EnsureRead(file,data);
|
||||
string name2 = System.Text.Encoding.UTF8.GetString(data);
|
||||
int chunkId = ReadBigEndianIntenger(file);
|
||||
classes.ClassEntries.Add(new ClassEntry(){Modifier = (byte)modifier, Name = name2, ChunkId = chunkId});
|
||||
}
|
||||
Classes.Add(classes);
|
||||
}
|
||||
int chunks = ReadBigEndianIntenger(file);
|
||||
for(int i = 0;i<chunks;i++)
|
||||
{
|
||||
Chunk chunk = new Chunk();
|
||||
|
||||
int argCount = ReadBigEndianIntenger(file);
|
||||
for(int j = 0;j<argCount;j++)
|
||||
{
|
||||
int nameLen = ReadBigEndianIntenger(file);
|
||||
data = new byte[nameLen];
|
||||
EnsureRead(file,data);
|
||||
string name2 = System.Text.Encoding.UTF8.GetString(data);
|
||||
chunk.Arguments.Add(name2);
|
||||
}
|
||||
|
||||
int length = ReadBigEndianIntenger(file);
|
||||
var code = new byte[length];
|
||||
int offset = 0;
|
||||
int read0 = 0;
|
||||
do{
|
||||
read0 = Math.Min(length-offset,1024);
|
||||
if(read0 > 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -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}");
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\TLang.VM\TLang.VM.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
Binary file not shown.
Loading…
Reference in New Issue