Working on VM

This commit is contained in:
Mike Nolan 2023-07-28 19:11:09 -05:00
parent c48bd44bc3
commit 461b439d5b
84 changed files with 2283 additions and 118 deletions

26
ByteCodeTest/.vscode/launch.json vendored Normal file
View File

@ -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"
}
]
}

41
ByteCodeTest/.vscode/tasks.json vendored Normal file
View File

@ -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"
}
]
}

View File

@ -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>

10
ByteCodeTest/Program.cs Normal file
View File

@ -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));
}

1
ByteCodeTest/app.tlang Normal file
View File

@ -0,0 +1 @@
37+5;

BIN
ByteCodeTest/app.tvm Normal file

Binary file not shown.

View File

@ -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));
}
}
}
}
}

View File

@ -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>

View File

@ -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>();
}
}

View File

@ -0,0 +1,8 @@
namespace TLang.Common
{
public interface ILabelable
{
string Key {get;set;}
int Value {get;set;}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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)
{
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>

View File

@ -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;}
}
}

View File

@ -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}";
}
}
}

View File

@ -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
{ {

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -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>();
} }
} }

View File

@ -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;
} }

View File

@ -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];
} }

View File

@ -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)
{ {

View File

@ -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;
} }

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -0,0 +1,6 @@
namespace TLang.Parser
{
public class FalseNode : SymbolNode
{
}
}

View File

@ -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;
}
}
}

View File

@ -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;

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -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;}

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -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)
{ {

6
TLang.Parser/NullNode.cs Normal file
View File

@ -0,0 +1,6 @@
namespace TLang.Parser
{
public class NullNode : SymbolNode
{
}
}

View File

@ -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)
{ {

View File

@ -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)
{ {

View File

@ -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>();

View File

@ -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)
{ {

6
TLang.Parser/TrueNode.cs Normal file
View File

@ -0,0 +1,6 @@
namespace TLang.Parser
{
public class TrueNode : SymbolNode
{
}
}

View File

@ -0,0 +1,6 @@
namespace TLang.Parser
{
public class UndefinedNode : SymbolNode
{
}
}

View File

@ -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)
{ {

11
TLang.VM/Chunk.cs Normal file
View File

@ -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;}
}
}

211
TLang.VM/ChunkExecuter.cs Normal file
View File

@ -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);
}
}
}

12
TLang.VM/Class.cs Normal file
View File

@ -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>();
}
}

18
TLang.VM/ClassEntry.cs Normal file
View File

@ -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;}
}
}

View File

@ -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();
}
}
}

15
TLang.VM/ClassMethod.cs Normal file
View File

@ -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;}
}
}

View File

@ -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();
}
}
}

8
TLang.VM/Function.cs Normal file
View File

@ -0,0 +1,8 @@
namespace TLang.VM
{
public class Function
{
public string Name {get;set;}
public int ChunkId {get;set;}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

7
TLang.VM/TCallable.cs Normal file
View File

@ -0,0 +1,7 @@
namespace TLang.VM
{
public abstract class TCallable : TObject
{
public abstract TObject Execute(params TObject[] args);
}
}

View File

@ -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();
}
}
}

22
TLang.VM/TClosure.cs Normal file
View File

@ -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);
}
}
}

11
TLang.VM/TLang.VM.csproj Normal file
View File

@ -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>

View File

@ -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;
}
}

View File

@ -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();
}
}

6
TLang.VM/TNull.cs Normal file
View File

@ -0,0 +1,6 @@
namespace TLang.VM
{
public class TNull : TObject
{
}
}

12
TLang.VM/TNumber.cs Normal file
View File

@ -0,0 +1,12 @@
namespace TLang.VM
{
public class TNumber : TObject
{
public double Value {get;set;}
public TNumber(double value)
{
this.Value = value;
}
}
}

6
TLang.VM/TObject.cs Normal file
View File

@ -0,0 +1,6 @@
namespace TLang.VM
{
public class TObject
{
}
}

12
TLang.VM/TString.cs Normal file
View File

@ -0,0 +1,12 @@
namespace TLang.VM
{
public class TString : TObject
{
public string Value {get;set;}
public TString(string value)
{
this.Value = value;
}
}
}

6
TLang.VM/TUndefined.cs Normal file
View File

@ -0,0 +1,6 @@
namespace TLang.VM
{
public class TUndefined : TObject
{
}
}

151
TLang.VM/TVMFile.cs Normal file
View File

@ -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;
}
}
}

26
VMTest/.vscode/launch.json vendored Normal file
View File

@ -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"
}
]
}

41
VMTest/.vscode/tasks.json vendored Normal file
View File

@ -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"
}
]
}

10
VMTest/Program.cs Normal file
View File

@ -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}");
}

14
VMTest/VMTest.csproj Normal file
View File

@ -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>

BIN
VMTest/app.tvm Normal file

Binary file not shown.