...
This commit is contained in:
@@ -238,7 +238,7 @@ public partial class QBEGenerator
|
||||
|
||||
private Val EmitVariableIdent(BoundVariableIdent variableIdent)
|
||||
{
|
||||
return _variables.Single(v => v.Name == variableIdent.Name).Val;
|
||||
return Scope.Lookup(variableIdent.Name);
|
||||
}
|
||||
|
||||
private Val EmitLiteral(BoundLiteral literal)
|
||||
|
||||
@@ -47,31 +47,6 @@ public partial class QBEGenerator
|
||||
EmitCopyIntoOrInitialize(assignment.Value, destination.Name);
|
||||
}
|
||||
|
||||
private void EmitBlock(BoundBlock block, List<Variable>? variables = null)
|
||||
{
|
||||
_variableScopes.Push(_variables.Count);
|
||||
if (variables != null)
|
||||
{
|
||||
foreach (var variable in variables)
|
||||
{
|
||||
_variables.Push(variable);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var statement in block.Statements.Where(_ => _codeIsReachable))
|
||||
{
|
||||
EmitStatement(statement);
|
||||
}
|
||||
|
||||
var count = _variableScopes.Pop();
|
||||
while (_variableScopes.Count > count)
|
||||
{
|
||||
_variableScopes.Pop();
|
||||
}
|
||||
|
||||
_codeIsReachable = true;
|
||||
}
|
||||
|
||||
private void EmitBreak()
|
||||
{
|
||||
_writer.Indented($"jmp {_breakLabels.Peek()}");
|
||||
@@ -132,7 +107,7 @@ public partial class QBEGenerator
|
||||
EmitStore(variableDeclaration.Assignment.Value.Type, value, name);
|
||||
}
|
||||
|
||||
_variables.Push(new Variable(variableDeclaration.Name, new Val(name, variableDeclaration.Type, ValKind.Pointer)));
|
||||
Scope.Declare(variableDeclaration.Name, new Val(name, variableDeclaration.Type, ValKind.Pointer));
|
||||
}
|
||||
|
||||
private void EmitWhile(BoundWhile whileStatement)
|
||||
|
||||
@@ -12,14 +12,13 @@ public partial class QBEGenerator
|
||||
private readonly BoundDefinitionTable _definitionTable;
|
||||
private readonly QBEWriter _writer;
|
||||
|
||||
private List<CStringLiteral> _cStringLiterals = [];
|
||||
private List<StringLiteral> _stringLiterals = [];
|
||||
private Stack<string> _breakLabels = [];
|
||||
private Stack<string> _continueLabels = [];
|
||||
private Queue<(BoundAnonymousFunc Func, string Name)> _anonymousFunctions = [];
|
||||
private Dictionary<BoundTraitFuncImpl, string> _implFunctions = [];
|
||||
private Stack<Variable> _variables = [];
|
||||
private Stack<int> _variableScopes = [];
|
||||
private readonly List<CStringLiteral> _cStringLiterals = [];
|
||||
private readonly List<StringLiteral> _stringLiterals = [];
|
||||
private readonly Stack<string> _breakLabels = [];
|
||||
private readonly Stack<string> _continueLabels = [];
|
||||
private readonly Queue<(BoundAnonymousFunc Func, string Name)> _anonymousFunctions = [];
|
||||
private readonly Dictionary<BoundTraitFuncImpl, string> _implFunctions = [];
|
||||
private readonly Stack<Scope> _scopes = [];
|
||||
private int _tmpIndex;
|
||||
private int _labelIndex;
|
||||
private int _anonymousFuncIndex;
|
||||
@@ -28,6 +27,8 @@ public partial class QBEGenerator
|
||||
private int _implFuncNameIndex;
|
||||
private bool _codeIsReachable = true;
|
||||
|
||||
private Scope Scope => _scopes.Peek();
|
||||
|
||||
public QBEGenerator(BoundSyntaxTree syntaxTree, BoundDefinitionTable definitionTable, string file)
|
||||
{
|
||||
_syntaxTree = syntaxTree;
|
||||
@@ -37,14 +38,13 @@ public partial class QBEGenerator
|
||||
|
||||
public string Emit()
|
||||
{
|
||||
_cStringLiterals = [];
|
||||
_stringLiterals = [];
|
||||
_breakLabels = [];
|
||||
_continueLabels = [];
|
||||
_anonymousFunctions = [];
|
||||
_implFunctions = [];
|
||||
_variables = [];
|
||||
_variableScopes = [];
|
||||
_cStringLiterals.Clear();
|
||||
_stringLiterals.Clear();
|
||||
_breakLabels.Clear();
|
||||
_continueLabels.Clear();
|
||||
_anonymousFunctions.Clear();
|
||||
_implFunctions.Clear();
|
||||
_scopes.Clear();
|
||||
_tmpIndex = 0;
|
||||
_labelIndex = 0;
|
||||
_anonymousFuncIndex = 0;
|
||||
@@ -347,18 +347,15 @@ public partial class QBEGenerator
|
||||
return "l";
|
||||
}
|
||||
|
||||
private void EmitFuncDefinition(string name, IEnumerable<BoundFuncParameter> parameters, NubType returnType, BoundBlock body)
|
||||
private void EmitFuncDefinition(string name, IReadOnlyList<BoundFuncParameter> parameters, NubType returnType, BoundBlock body)
|
||||
{
|
||||
var parameterArray = parameters.ToArray();
|
||||
|
||||
_variables.Clear();
|
||||
_variableScopes.Clear();
|
||||
_labelIndex = 0;
|
||||
_tmpIndex = 0;
|
||||
|
||||
var builder = new StringBuilder();
|
||||
|
||||
builder.Append("export function ");
|
||||
|
||||
if (returnType is not NubVoidType)
|
||||
{
|
||||
builder.Append(FuncQBETypeName(returnType) + ' ');
|
||||
@@ -366,15 +363,16 @@ public partial class QBEGenerator
|
||||
|
||||
builder.Append(name);
|
||||
|
||||
var parameterStrings = parameterArray.Select(x => FuncQBETypeName(x.Type) + $" %{x.Name}");
|
||||
|
||||
builder.Append($"({string.Join(", ", parameterStrings)})");
|
||||
builder.Append($"({string.Join(", ", parameters.Select(x => FuncQBETypeName(x.Type) + $" %{x.Name}"))})");
|
||||
|
||||
_writer.StartFunction(builder.ToString());
|
||||
|
||||
var parameterVars = parameterArray.Select(parameter => new Variable(parameter.Name, new Val("%" + parameter.Name, parameter.Type, ValKind.Direct))).ToList();
|
||||
var scope = new Scope();
|
||||
|
||||
EmitBlock(body, parameterVars);
|
||||
foreach (var parameter in parameters)
|
||||
{
|
||||
scope.Declare(parameter.Name, new Val("%" + parameter.Name, parameter.Type, ValKind.Direct));
|
||||
}
|
||||
|
||||
if (body.Statements.LastOrDefault() is not BoundReturn)
|
||||
{
|
||||
@@ -445,6 +443,20 @@ public partial class QBEGenerator
|
||||
_writer.WriteLine("}");
|
||||
}
|
||||
|
||||
private void EmitBlock(BoundBlock block, Scope? scope = null)
|
||||
{
|
||||
_scopes.Push(scope ?? Scope.SubScope());
|
||||
|
||||
foreach (var statement in block.Statements.Where(_ => _codeIsReachable))
|
||||
{
|
||||
EmitStatement(statement);
|
||||
}
|
||||
|
||||
_scopes.Pop();
|
||||
|
||||
_codeIsReachable = true;
|
||||
}
|
||||
|
||||
private string EmitUnwrap(Val val)
|
||||
{
|
||||
return val.Kind switch
|
||||
@@ -525,29 +537,49 @@ public partial class QBEGenerator
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal class StringLiteral(string value, string name)
|
||||
public class StringLiteral(string value, string name)
|
||||
{
|
||||
public string Value { get; } = value;
|
||||
public string Name { get; } = name;
|
||||
}
|
||||
|
||||
internal class CStringLiteral(string value, string name)
|
||||
public class CStringLiteral(string value, string name)
|
||||
{
|
||||
public string Value { get; } = value;
|
||||
public string Name { get; } = name;
|
||||
}
|
||||
|
||||
internal class Variable(string name, Val val)
|
||||
public record Val(string Name, NubType Type, ValKind Kind, MethodCallContext? FuncCallContext = null);
|
||||
|
||||
public class Scope(Scope? parent = null)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public Val Val { get; } = val;
|
||||
private readonly Dictionary<string, Val> _variables = [];
|
||||
|
||||
public Val Lookup(string name)
|
||||
{
|
||||
var variable = _variables.GetValueOrDefault(name);
|
||||
if (variable != null)
|
||||
{
|
||||
return variable;
|
||||
}
|
||||
|
||||
return parent?.Lookup(name) ?? throw new UnreachableException($"Variable '{name}' not found");
|
||||
}
|
||||
|
||||
public void Declare(string name, Val value)
|
||||
{
|
||||
_variables.Add(name, value);
|
||||
}
|
||||
|
||||
public Scope SubScope()
|
||||
{
|
||||
return new Scope(this);
|
||||
}
|
||||
}
|
||||
|
||||
internal record Val(string Name, NubType Type, ValKind Kind, MethodCallContext? FuncCallContext = null);
|
||||
public record MethodCallContext(Val ThisArg);
|
||||
|
||||
internal record MethodCallContext(Val ThisArg);
|
||||
|
||||
internal enum ValKind
|
||||
public enum ValKind
|
||||
{
|
||||
Pointer,
|
||||
Direct,
|
||||
|
||||
Reference in New Issue
Block a user