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);
|
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)
|
public void Add(int i=1)
|
||||||
{
|
{
|
||||||
|
@ -78,7 +74,7 @@ namespace TLang.Lexer
|
||||||
|
|
||||||
foreach(var item in tokenText)
|
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];
|
token = Tokens[Offset];
|
||||||
if(consumeIfTrue) Offset++;
|
if(consumeIfTrue) Offset++;
|
||||||
|
@ -90,15 +86,15 @@ namespace TLang.Lexer
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LexToken NextEntry
|
public LexToken NextEntry()
|
||||||
{
|
{
|
||||||
get {
|
|
||||||
if(Offset < Tokens.Count)
|
if(Offset < Tokens.Count)
|
||||||
{
|
{
|
||||||
return Tokens[Offset++];
|
return Tokens[Offset++];
|
||||||
}
|
}
|
||||||
return LexToken.Empty;
|
return LexToken.Empty;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public LexToken PeekEntry
|
public LexToken PeekEntry
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class AddNode : Node
|
public class AddNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public AddNode(Node left, Node right)
|
public AddNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class BAndNode : Node
|
public class BAndNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public BAndNode(Node left, Node right)
|
public BAndNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class BOrNode : Node
|
public class BOrNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public BOrNode(Node left, Node right)
|
public BOrNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,6 +4,6 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class CallNode : SymbolNode
|
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 class CaseNode : Node
|
||||||
{
|
{
|
||||||
public Node Variable {get;set;}
|
public Node Variable {get;set;}
|
||||||
public Node Body {get;set;}
|
|
||||||
|
|
||||||
public CaseNode(Node expr, Node node)
|
public CaseNode(Node expr)
|
||||||
{
|
{
|
||||||
Variable = expr;
|
Variable = expr;
|
||||||
Body = node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,11 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class CharNode : Node
|
public class CharNode : Node
|
||||||
{
|
{
|
||||||
public string Text {get;set;}
|
public char Text {get;set;}
|
||||||
|
|
||||||
public CharNode(string text)
|
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)
|
private Node ParseNode(bool isRoot=false,bool inCase=false)
|
||||||
{
|
{
|
||||||
|
|
||||||
ScopeNode node = new ScopeNode();
|
|
||||||
node.LineInfo = Context.CurrentLineInfo;
|
|
||||||
|
|
||||||
|
if(Context.NextEntries(true,"{").Success || isRoot)
|
||||||
while(Context.Offset < Context.Tokens.Count && (isRoot || !Context.NextEntries(true,"}").Success))
|
|
||||||
{
|
|
||||||
if(Context.NextEntries(true,"{").Success)
|
|
||||||
{
|
{
|
||||||
node.Add(ParseNode());
|
ScopeNode node = new ScopeNode();
|
||||||
}
|
node.LineInfo = Context.CurrentLineInfo;
|
||||||
node.Add(ParseAssigable());
|
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()
|
private Node ParseAssigable()
|
||||||
|
@ -233,7 +243,7 @@ namespace TLang.Parser
|
||||||
|
|
||||||
private Node ParseRo()
|
private Node ParseRo()
|
||||||
{
|
{
|
||||||
Node expr = ParseRo();
|
Node expr = ParseShift();
|
||||||
while(Context.NextEntryIsAnyOf(true,out var token,"<","<=",">",">="))
|
while(Context.NextEntryIsAnyOf(true,out var token,"<","<=",">",">="))
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -332,7 +342,7 @@ namespace TLang.Parser
|
||||||
private Node ParseValue()
|
private Node ParseValue()
|
||||||
{
|
{
|
||||||
var doc = Context.PopDocumentation();
|
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.IsString) return new StringNode(token.Text){LineInfo = token.Position};
|
||||||
if(token.IsChar) return new CharNode(token.Text){LineInfo = token.Position};
|
if(token.IsChar) return new CharNode(token.Text){LineInfo = token.Position};
|
||||||
if(token.Text == "(")
|
if(token.Text == "(")
|
||||||
|
@ -345,25 +355,25 @@ namespace TLang.Parser
|
||||||
if(token.Text == "class")
|
if(token.Text == "class")
|
||||||
{
|
{
|
||||||
ClassNode classInstance = new ClassNode();
|
ClassNode classInstance = new ClassNode();
|
||||||
classInstance.Name = Context.NextEntry.Text;
|
classInstance.Name = Context.NextEntry().Text;
|
||||||
classInstance.Documentation = doc;
|
classInstance.Documentation = doc;
|
||||||
|
|
||||||
|
|
||||||
if(Context.NextEntries(true,":").Success)
|
if(Context.NextEntries(true,":").Success)
|
||||||
{
|
{
|
||||||
|
|
||||||
classInstance.InheritsFrom = Context.NextEntry.Text;
|
classInstance.InheritsFrom = Context.NextEntry().Text;
|
||||||
|
|
||||||
}
|
}
|
||||||
Context.NextEntries(true,"{");
|
Context.NextEntries(true,"{");
|
||||||
while(Context.MoreTokens && !Context.NextEntries(true,"}").Success)
|
while(Context.MoreTokens && !Context.NextEntries(true,"}").Success)
|
||||||
{
|
{
|
||||||
var doc2 = Context.PopDocumentation();
|
var doc2 = Context.PopDocumentation();
|
||||||
var token2 = Context.NextEntry;
|
var token2 = Context.NextEntry();
|
||||||
var modifier = token2.Text;
|
var modifier = token2.Text;
|
||||||
if(Context.NextEntryIsAnyOf(true,out var token3,"func","abst"))
|
if(Context.NextEntryIsAnyOf(true,out var token3,"func","abst"))
|
||||||
{
|
{
|
||||||
var name = Context.NextEntry.Text;
|
var name = Context.NextEntry().Text;
|
||||||
if(Context.NextEntries(true,"(").Success)
|
if(Context.NextEntries(true,"(").Success)
|
||||||
{
|
{
|
||||||
var pos = Context.PeekEntry.Position;
|
var pos = Context.PeekEntry.Position;
|
||||||
|
@ -374,16 +384,8 @@ namespace TLang.Parser
|
||||||
|
|
||||||
if(Context.Offset < Context.Tokens.Count)
|
if(Context.Offset < Context.Tokens.Count)
|
||||||
{
|
{
|
||||||
var n0 = ParseNode();
|
args.Add(Context.NextEntry().Text);
|
||||||
var n= n0 as GetVariableNode;
|
|
||||||
if(n != null)
|
|
||||||
{
|
|
||||||
args.Add(n.Name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new CompilerError("Argument must be a GetVariableNode",n0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ClassEntryNode nod=new ClassEntryNode(){LineInfo = token2.Position};
|
ClassEntryNode nod=new ClassEntryNode(){LineInfo = token2.Position};
|
||||||
|
@ -399,7 +401,7 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
ClassEntryNode nod = new ClassEntryNode(){LineInfo = token2.Position};
|
ClassEntryNode nod = new ClassEntryNode(){LineInfo = token2.Position};
|
||||||
nod.Documentation = doc2;
|
nod.Documentation = doc2;
|
||||||
nod.Name = Context.NextEntry.Text;
|
nod.Name = Context.NextEntry().Text;
|
||||||
if(!Context.NextEntries(true,"=").Success) throw new CompilerError("Invalid member",classInstance);
|
if(!Context.NextEntries(true,"=").Success) throw new CompilerError("Invalid member",classInstance);
|
||||||
|
|
||||||
nod.Modifier = modifier;
|
nod.Modifier = modifier;
|
||||||
|
@ -426,14 +428,14 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
var expr = ParseNode();
|
var expr = ParseNode();
|
||||||
if(!Context.NextEntries(true,":").Success) throw new CompilerError("Missing :",expr);
|
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")
|
if(token.Text == "default")
|
||||||
{
|
{
|
||||||
var cur = Context.CurrentLineInfo;
|
var cur = Context.CurrentLineInfo;
|
||||||
var r=Context.NextEntries(true,":");
|
var r=Context.NextEntries(true,":");
|
||||||
if(!r.Success) throw new CompilerError("Missing :",new Node(){LineInfo = cur});
|
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 == "-")
|
if(token.Text == "-")
|
||||||
{
|
{
|
||||||
|
@ -451,7 +453,7 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
if(Context.NextEntries(true,".").Success)
|
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))
|
if(!entry.IsChar && !entry.IsDocumentation && !entry.IsEmpty && !entry.IsString && double.TryParse($"{number}.{entry.Text}",out var number2))
|
||||||
{
|
{
|
||||||
return new ConstNumberNode(number2);
|
return new ConstNumberNode(number2);
|
||||||
|
@ -475,16 +477,9 @@ namespace TLang.Parser
|
||||||
|
|
||||||
if(Context.Offset < Context.Tokens.Count)
|
if(Context.Offset < Context.Tokens.Count)
|
||||||
{
|
{
|
||||||
var n0 = ParseNode();
|
|
||||||
var n= n0 as GetVariableNode;
|
args.Add(Context.NextEntry().Text);
|
||||||
if(n != null)
|
|
||||||
{
|
|
||||||
args.Add(n.Name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new CompilerError("Argument must be a GetVariableNode",n0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ClosureNode(args,ParseNode());
|
return new ClosureNode(args,ParseNode());
|
||||||
|
@ -597,7 +592,7 @@ namespace TLang.Parser
|
||||||
}
|
}
|
||||||
while(Context.MoreTokens && Context.NextEntries(true,".").Success)
|
while(Context.MoreTokens && Context.NextEntries(true,".").Success)
|
||||||
{
|
{
|
||||||
var token2 = Context.NextEntry;
|
var token2 = Context.NextEntry();
|
||||||
|
|
||||||
if(Context.MoreTokens && Context.NextEntries(true,"(").Success)
|
if(Context.MoreTokens && Context.NextEntries(true,"(").Success)
|
||||||
{
|
{
|
||||||
|
@ -641,29 +636,23 @@ namespace TLang.Parser
|
||||||
SymbolNode ret = new NullNode();
|
SymbolNode ret = new NullNode();
|
||||||
if(token.Text == "func")
|
if(token.Text == "func")
|
||||||
{
|
{
|
||||||
var res = new GetVariableNode(Context.NextEntry.Text);
|
var funcName= Context.NextEntry().Text;
|
||||||
if(Context.MoreTokens && Context.NextEntries(true,"(").Success)
|
if(Context.MoreTokens && Context.NextEntries(true,"(").Success)
|
||||||
{
|
{
|
||||||
List<string> args=new List<string>();
|
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.NextEntries(true,",").Success) continue;
|
||||||
|
|
||||||
if(Context.Offset < Context.Tokens.Count)
|
if(Context.Offset < Context.Tokens.Count)
|
||||||
{
|
{
|
||||||
var n0 = ParseNode();
|
|
||||||
var n= n0 as GetVariableNode;
|
args.Add(Context.NextEntry().Text);
|
||||||
if(n != null)
|
|
||||||
{
|
|
||||||
args.Add(n.Name);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new CompilerError("Argument must be a GetVariableNode",n0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new SetVariableNode( res,new ClosureNode(args,ParseNode()));
|
return new FunctionDeclaritionNode( funcName,new ClosureNode(args,ParseNode())){LineInfo=token.Position};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(token.Text == "null")
|
if(token.Text == "null")
|
||||||
|
@ -695,7 +684,7 @@ namespace TLang.Parser
|
||||||
}
|
}
|
||||||
while(Context.MoreTokens && Context.NextEntries(true,".").Success)
|
while(Context.MoreTokens && Context.NextEntries(true,".").Success)
|
||||||
{
|
{
|
||||||
var token2 = Context.NextEntry;
|
var token2 = Context.NextEntry();
|
||||||
|
|
||||||
if(Context.MoreTokens && Context.NextEntries(true,"(").Success)
|
if(Context.MoreTokens && Context.NextEntries(true,"(").Success)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,11 +4,10 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class DefaultNode : Node
|
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
|
public class DivideNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public DivideNode(Node left, Node right)
|
public DivideNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class EqualsNode : Node
|
public class EqualsNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public EqualsNode(Node left, Node right)
|
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
|
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;
|
Symbol = symbol;
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class GreaterThanEqualsNode : Node
|
public class GreaterThanEqualsNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public GreaterThanEqualsNode(Node left, Node right)
|
public GreaterThanEqualsNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class GreaterThanNode : Node
|
public class GreaterThanNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public GreaterThanNode(Node left, Node right)
|
public GreaterThanNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace TLang.Parser
|
namespace TLang.Parser
|
||||||
{
|
{
|
||||||
internal class IfNode : Node
|
public class IfNode : Node
|
||||||
{
|
{
|
||||||
public Node Condition {get;set;}
|
public Node Condition {get;set;}
|
||||||
public Node Yes {get;set;}
|
public Node Yes {get;set;}
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class LAndNode : Node
|
public class LAndNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public LAndNode(Node left, Node right)
|
public LAndNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class LOrNode : Node
|
public class LOrNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public LOrNode(Node left, Node right)
|
public LOrNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class LeftShiftNode : Node
|
public class LeftShiftNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public LeftShiftNode(Node left, Node right)
|
public LeftShiftNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class LessThanEqualsNode : Node
|
public class LessThanEqualsNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public LessThanEqualsNode(Node left, Node right)
|
public LessThanEqualsNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class LessThanNode : Node
|
public class LessThanNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public LessThanNode(Node left, Node right)
|
public LessThanNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class ModuloNode : Node
|
public class ModuloNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public ModuloNode(Node left, Node right)
|
public ModuloNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class MultiplyNode : Node
|
public class MultiplyNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public MultiplyNode(Node left, Node right)
|
public MultiplyNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class NotEqualsNode : Node
|
public class NotEqualsNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public NotEqualsNode(Node left, Node right)
|
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
|
public class PowNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public PowNode(Node left, Node right)
|
public PowNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class RightShiftNode : Node
|
public class RightShiftNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public RightShiftNode(Node left, Node right)
|
public RightShiftNode(Node left, Node right)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class ScopeNode : Node
|
public class ScopeNode : Node
|
||||||
{
|
{
|
||||||
|
public bool RootScope {get;set;}=false;
|
||||||
public bool IsSwitchScope {get;set;}
|
public bool IsSwitchScope {get;set;}
|
||||||
public Node SwitchCondition {get;set;}=new Node();
|
public Node SwitchCondition {get;set;}=new Node();
|
||||||
public List<Node> Nodes {get;set;}=new List<Node>();
|
public List<Node> Nodes {get;set;}=new List<Node>();
|
||||||
|
|
|
@ -2,8 +2,8 @@ namespace TLang.Parser
|
||||||
{
|
{
|
||||||
public class SubtractNode : Node
|
public class SubtractNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public SubtractNode(Node left, Node right)
|
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
|
public class XOrNode : Node
|
||||||
{
|
{
|
||||||
private Node Left {get;set;}
|
public Node Left {get;set;}
|
||||||
private Node Right {get;set;}
|
public Node Right {get;set;}
|
||||||
|
|
||||||
public XOrNode(Node left, Node right)
|
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