proper scopes

This commit is contained in:
nub31
2026-02-10 23:26:22 +01:00
parent 924bdae89b
commit 7daccba9f3
2 changed files with 73 additions and 42 deletions

View File

@@ -180,7 +180,7 @@ public class ModuleGraph
var astModuleCache = new Dictionary<Ast, Module>();
// First pass: Register modules from ast
// Second pass: Register modules from ast
foreach (var ast in asts)
{
if (!modules.ContainsKey(ast.ModuleName.Ident))
@@ -191,7 +191,7 @@ public class ModuleGraph
}
}
// Second pass: Register struct types without fields
// Third pass: Register struct types without fields
foreach (var ast in asts)
{
var module = astModuleCache[ast];
@@ -204,7 +204,7 @@ public class ModuleGraph
}
}
// Third pass: Resolve struct fields
// Fourth pass: Resolve struct fields
foreach (var ast in asts)
{
var module = astModuleCache[ast];
@@ -219,7 +219,7 @@ public class ModuleGraph
}
}
// Fourth pass: Register identifiers
// Fifth pass: Register identifiers
foreach (var ast in asts)
{
var module = astModuleCache[ast];

View File

@@ -19,7 +19,7 @@ public class TypeChecker
private readonly string moduleName;
private readonly NodeDefinitionFunc function;
private readonly ModuleGraph moduleGraph;
private readonly Scope scope = new(null);
private readonly Scope scope = new();
private TypedNodeDefinitionFunc? CheckFunction(out List<Diagnostic> diagnostics)
{
@@ -30,48 +30,50 @@ public class TypeChecker
TypedNodeStatement? body = null;
NubType? returnType = null;
foreach (var parameter in function.Parameters)
using (scope.EnterScope())
{
scope.DeclareIdentifier(parameter.Name.Ident, ResolveType(parameter.Type));
foreach (var parameter in function.Parameters)
{
NubType parameterType;
try
{
parameterType = ResolveType(parameter.Type);
}
catch (CompileException e)
{
diagnostics.Add(e.Diagnostic);
invalidParameter = true;
continue;
}
scope.DeclareIdentifier(parameter.Name.Ident, parameterType);
parameters.Add(new TypedNodeDefinitionFunc.Param(parameter.Tokens, parameter.Name, parameterType));
}
try
{
parameters.Add(CheckDefinitionFuncParameter(parameter));
body = CheckStatement(function.Body);
}
catch (CompileException e)
{
diagnostics.Add(e.Diagnostic);
invalidParameter = true;
}
}
try
{
body = CheckStatement(function.Body);
}
catch (CompileException e)
{
diagnostics.Add(e.Diagnostic);
}
try
{
returnType = ResolveType(function.ReturnType);
}
catch (CompileException e)
{
diagnostics.Add(e.Diagnostic);
}
try
{
returnType = ResolveType(function.ReturnType);
if (body == null || returnType == null || invalidParameter)
return null;
return new TypedNodeDefinitionFunc(function.Tokens, moduleName, function.Name, parameters, body, returnType);
}
catch (CompileException e)
{
diagnostics.Add(e.Diagnostic);
}
if (body == null || returnType == null || invalidParameter)
return null;
return new TypedNodeDefinitionFunc(function.Tokens, moduleName, function.Name, parameters, body, returnType);
}
private TypedNodeDefinitionFunc.Param CheckDefinitionFuncParameter(NodeDefinitionFunc.Param node)
{
return new TypedNodeDefinitionFunc.Param(node.Tokens, node.Name, ResolveType(node.Type));
}
private TypedNodeStatement CheckStatement(NodeStatement node)
@@ -96,7 +98,11 @@ public class TypeChecker
private TypedNodeStatementBlock CheckStatementBlock(NodeStatementBlock statement)
{
return new TypedNodeStatementBlock(statement.Tokens, statement.Statements.Select(CheckStatement).ToList());
using (scope.EnterScope())
{
var statements = statement.Statements.Select(CheckStatement).ToList();
return new TypedNodeStatementBlock(statement.Tokens, statements);
}
}
private TypedNodeStatementFuncCall CheckStatementExpression(NodeStatementExpression statement)
@@ -406,20 +412,45 @@ public class TypeChecker
return customType;
}
private class Scope(Scope? parent)
private sealed class Scope
{
private readonly Dictionary<string, NubType> identifiers = new();
private readonly Stack<Dictionary<string, NubType>> scopes = new();
public IDisposable EnterScope()
{
scopes.Push([]);
return new ScopeGuard(this);
}
public void DeclareIdentifier(string name, NubType type)
{
identifiers.Add(name, type);
scopes.Peek().Add(name, type);
}
public NubType? GetIdentifierType(string name)
{
return identifiers.TryGetValue(name, out var type)
? type
: parent?.GetIdentifierType(name);
foreach (var scope in scopes)
{
if (scope.TryGetValue(name, out var type))
{
return type;
}
}
return null;
}
private void ExitScope()
{
scopes.Pop();
}
private sealed class ScopeGuard(Scope owner) : IDisposable
{
public void Dispose()
{
owner.ExitScope();
}
}
}
}