FunctionContext
using CLanguage.Syntax;
using CLanguage.Types;
using System;
using System.Collections.Generic;
using System.Linq;
namespace CLanguage.Interpreter
{
internal class FunctionContext : EmitContext
{
private class BlockLocals
{
public int StartIndex;
public int Length;
}
private Executable exe;
private CompiledFunction fexe;
private EmitContext context;
private List<Block> blocks;
private Dictionary<Block, BlockLocals> blockLocals;
private List<CompiledVariable> allLocals;
public IEnumerable<CompiledVariable> LocalVariables => allLocals;
public FunctionContext(Executable exe, CompiledFunction fexe, EmitContext context)
: base(context.MachineInfo, context.Report, fexe)
{
this.exe = exe;
this.fexe = fexe;
this.context = context;
blocks = new List<Block>();
blockLocals = new Dictionary<Block, BlockLocals>();
allLocals = new List<CompiledVariable>();
}
public override ResolvedVariable ResolveVariable(string name, CType[] argTypes)
{
for (int i = 0; i < fexe.FunctionType.Parameters.Count; i++) {
CFunctionType.Parameter parameter = fexe.FunctionType.Parameters[i];
if (parameter.Name == name)
return new ResolvedVariable(VariableScope.Arg, parameter.Offset, fexe.FunctionType.Parameters[i].ParameterType);
}
foreach (Block item in Enumerable.Reverse(blocks)) {
BlockLocals blockLocals = this.blockLocals[item];
for (int j = 0; j < blockLocals.Length; j++) {
int index = blockLocals.StartIndex + j;
if (allLocals[index].Name == name)
return new ResolvedVariable(VariableScope.Local, allLocals[index].Offset, allLocals[index].VariableType);
}
}
for (int k = 0; k < exe.Globals.Count; k++) {
if (exe.Globals[k].Name == name)
return new ResolvedVariable(VariableScope.Global, exe.Globals[k].Offset, exe.Globals[k].VariableType);
}
BaseFunction baseFunction = null;
int address = -1;
int num = 0;
for (int l = 0; l < exe.Functions.Count; l++) {
BaseFunction baseFunction2 = exe.Functions[l];
if (baseFunction2.Name == name && string.IsNullOrEmpty(baseFunction2.NameContext)) {
int num2 = baseFunction2.FunctionType.ScoreParameterTypeMatches(argTypes);
if (num2 > num) {
baseFunction = baseFunction2;
address = l;
num = num2;
}
}
}
if (baseFunction != null)
return new ResolvedVariable(baseFunction, address);
context.Report.Error(103, "The name '" + name + "' does not exist in the current context");
return null;
}
public override ResolvedVariable ResolveMethodFunction(CStructType structType, CStructMethod method)
{
CFunctionType otherType;
if ((otherType = (method.MemberType as CFunctionType)) != null) {
string nameContext = structType.Name;
((IEnumerable<BaseFunction>)exe.Functions).Select((Func<BaseFunction, int, (BaseFunction, int)>)((BaseFunction f, int i) => (f, i))).Where((Func<(BaseFunction, int), bool>)delegate((BaseFunction f, int i) x) {
if (x.f.NameContext == nameContext)
return x.f.Name == method.Name;
return false;
});
for (int j = 0; j < exe.Functions.Count; j++) {
BaseFunction baseFunction = exe.Functions[j];
if (baseFunction.NameContext == nameContext && baseFunction.Name == method.Name && baseFunction.FunctionType.ParameterTypesEqual(otherType))
return new ResolvedVariable(baseFunction, j);
}
}
context.Report.Error(9000, $"""{structType.Name}""{method.Name}""");
return null;
}
public override void BeginBlock(Block b)
{
blocks.Add(b);
BlockLocals value = new BlockLocals {
StartIndex = allLocals.Count,
Length = b.Variables.Count
};
blockLocals[b] = value;
allLocals.AddRange(b.Variables);
int num = 0;
foreach (CompiledVariable allLocal in allLocals) {
allLocal.Offset = num;
num += allLocal.VariableType.NumValues;
}
}
public override void EndBlock()
{
blocks.RemoveAt(blocks.Count - 1);
}
public override Label DefineLabel()
{
return new Label();
}
public override void EmitLabel(Label l)
{
l.Index = fexe.Instructions.Count;
}
public override void Emit(Instruction instruction)
{
fexe.Instructions.Add(instruction);
}
public override Value GetConstantMemory(string stringConstant)
{
return exe.GetConstantMemory(stringConstant);
}
}
}