CInterpreter
using CLanguage.Compiler;
using CLanguage.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
namespace CLanguage.Interpreter
{
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public class CInterpreter
{
private Executable exe;
[System.Runtime.CompilerServices.Nullable(2)]
private BaseFunction entrypoint;
public readonly Value[] Stack;
public int SP;
private readonly ExecutionFrame[] Frames;
private int FI;
public int CpuSpeed = 1000;
private static readonly BaseFunction unusedStackFrameFunction = new InternalFunction("unused", "", CFunctionType.VoidProcedure);
public Executable Executable => exe;
public int YieldedValue { get; set; }
public int SleepTime { get; set; }
public int RemainingTime { get; set; }
[System.Runtime.CompilerServices.Nullable(2)]
public ExecutionFrame ActiveFrame {
[System.Runtime.CompilerServices.NullableContext(2)]
get {
if (0 > FI || FI >= Frames.Length)
return null;
return Frames[FI];
}
}
public int CallStackDepth => FI;
public CInterpreter(Executable exe, int maxStack = 1024, int maxFrames = 24)
{
this.exe = exe;
Stack = new Value[maxStack];
Frames = (from i in Enumerable.Range(0, maxFrames)
select new ExecutionFrame(unusedStackFrameFunction)).ToArray();
}
public Value ReadMemory(int address)
{
return Stack[address];
}
public string ReadStringWithEncoding(int address, Encoding encoding)
{
byte b = (byte)Stack[address];
List<byte> list = new List<byte>();
while (b != 0) {
list.Add(b);
address++;
b = (byte)Stack[address];
}
byte[] array = list.ToArray();
return encoding.GetString(array, 0, array.Length);
}
public string ReadString(int address)
{
return ReadStringWithEncoding(address, Encoding.UTF8);
}
public Value ReadThis()
{
ExecutionFrame activeFrame = ActiveFrame;
if (activeFrame == null)
return 0;
if (!activeFrame.Function.FunctionType.IsInstance)
return 0;
int num = -1;
int num2 = activeFrame.FP + num;
return Stack[num2];
}
public Value ReadArg(int index)
{
ExecutionFrame activeFrame = ActiveFrame;
if (activeFrame == null)
return 0;
CFunctionType functionType = activeFrame.Function.FunctionType;
int num;
if (index < functionType.Parameters.Count)
num = functionType.Parameters[index].Offset;
else {
if (index != functionType.Parameters.Count || !functionType.IsInstance)
throw new ArgumentOutOfRangeException("Cannot read argument #" + index.ToString());
num = -1;
}
int num2 = activeFrame.FP + num;
return Stack[num2];
}
public void Call(Value functionAddress)
{
Call(exe.Functions[functionAddress.PointerValue]);
}
public void Call(BaseFunction function)
{
if (FI + 1 >= Frames.Length) {
string name = function.Name;
string text = ActiveFrame?.Function.Name ?? "?";
Reset();
throw new ExecutionException("Stack overflow while calling '" + name + "' from '" + text + "'");
}
FI++;
ExecutionFrame obj = Frames[FI];
obj.Function = function;
obj.FP = SP;
obj.IP = 0;
function.Init(this);
}
public void Push(Value value)
{
Stack[SP++] = value;
}
public void Yield(int yieldedValue)
{
YieldedValue = yieldedValue;
}
public void Return()
{
ExecutionFrame activeFrame = ActiveFrame;
if (activeFrame == null)
throw new InvalidOperationException("Cannot call Return with no ActiveFrame");
CFunctionType functionType = activeFrame.Function.FunctionType;
int num = 0;
foreach (CFunctionType.Parameter parameter in functionType.Parameters) {
num += parameter.ParameterType.NumValues;
}
if (functionType.IsInstance)
num++;
CompiledFunction compiledFunction = activeFrame.Function as CompiledFunction;
if (compiledFunction != null) {
foreach (CompiledVariable localVariable in compiledFunction.LocalVariables) {
num += localVariable.VariableType.NumValues;
}
}
int numValues = functionType.ReturnType.NumValues;
int num2 = SP - num;
int num3 = num2 - numValues;
for (int i = 0; i < numValues; i++) {
Stack[num3 + i] = Stack[SP - numValues + i];
}
SP = num2;
FI--;
}
public void Reset(string entrypoint)
{
this.entrypoint = exe.Functions.FirstOrDefault((BaseFunction x) => x.Name == entrypoint);
Reset();
}
private void Reset()
{
FI = -1;
SP = 0;
foreach (CompiledVariable global in exe.Globals) {
if (global.InitialValue != null) {
for (int i = 0; i < global.InitialValue.Length; i++) {
Stack[global.StackOffset + i] = global.InitialValue[i];
}
}
SP += global.VariableType.NumValues;
}
SleepTime = 0;
if (entrypoint != null)
Call(entrypoint);
}
public void Run()
{
Step(1000000);
}
public static void Run(string code)
{
CInterpreter cInterpreter = new CInterpreter(CCompiler.Compile(code), 1024, 24);
cInterpreter.Reset("main");
cInterpreter.Run();
}
[Obsolete("Please use Run() which Steps for 1 machine second.")]
public void Step()
{
Step(1000000);
}
public void Step(int microseconds)
{
if (ActiveFrame != null) {
if (microseconds <= SleepTime)
SleepTime -= microseconds;
else {
RemainingTime = microseconds - SleepTime;
SleepTime = 0;
try {
ExecutionFrame activeFrame = ActiveFrame;
while (activeFrame != null && RemainingTime > 0) {
RemainingTime -= CpuSpeed;
activeFrame.Function.Step(this, activeFrame);
activeFrame = ActiveFrame;
if (YieldedValue != 0)
break;
}
} catch (Exception) {
Reset();
throw;
}
}
}
}
public Value RunFunction(Value functionAddress, int microseconds)
{
Call(functionAddress);
return StepFunction(microseconds);
}
public Value RunFunction(Value functionAddress, Value arg0, int microseconds)
{
Push(arg0);
Call(functionAddress);
return StepFunction(microseconds);
}
public Value RunFunction(Value functionAddress, Value arg0, Value arg1, int microseconds)
{
Push(arg0);
Push(arg1);
Call(functionAddress);
return StepFunction(microseconds);
}
public Value RunFunction(Value functionAddress, Value arg0, Value arg1, Value arg2, int microseconds)
{
Push(arg0);
Push(arg1);
Push(arg2);
Call(functionAddress);
return StepFunction(microseconds);
}
private Value StepFunction(int microseconds)
{
if (ActiveFrame == null)
return 0;
int fI = FI;
CType cType = ActiveFrame?.Function.FunctionType.ReturnType;
if (microseconds <= SleepTime)
SleepTime -= microseconds;
else {
RemainingTime = microseconds - SleepTime;
SleepTime = 0;
try {
ExecutionFrame activeFrame = ActiveFrame;
while (activeFrame != null && FI >= fI && RemainingTime > 0) {
RemainingTime -= CpuSpeed;
activeFrame.Function.Step(this, activeFrame);
activeFrame = ActiveFrame;
if (YieldedValue != 0)
break;
}
} catch (Exception) {
Reset();
throw;
}
}
while (FI >= fI) {
CType cType2 = ActiveFrame?.Function.FunctionType.ReturnType;
if (cType2 == null)
break;
if (!cType2.IsVoid) {
int numValues = cType2.NumValues;
for (int i = 0; i < numValues; i++) {
Stack[SP++] = 0;
}
}
Return();
}
Value result = 0;
int num = cType?.NumValues ?? 0;
for (int j = 0; j < num; j++) {
result = Stack[--SP];
}
return result;
}
}
}