WIP: dev #1
@@ -24,7 +24,7 @@ public class TypeChecker
|
||||
private readonly NodeDefinitionFunc function;
|
||||
private NubType functionReturnType = null!;
|
||||
private readonly ModuleGraph moduleGraph;
|
||||
private readonly Scope scope = new();
|
||||
private readonly Stack<Dictionary<string, NubType>> scopes = new();
|
||||
|
||||
private TypedNodeDefinitionFunc? CheckFunction(out List<Diagnostic> diagnostics)
|
||||
{
|
||||
@@ -51,7 +51,7 @@ public class TypeChecker
|
||||
}
|
||||
}
|
||||
|
||||
using (scope.EnterScope())
|
||||
using (EnterScope())
|
||||
{
|
||||
foreach (var parameter in function.Parameters)
|
||||
{
|
||||
@@ -60,6 +60,7 @@ public class TypeChecker
|
||||
try
|
||||
{
|
||||
parameterType = ResolveType(parameter.Type);
|
||||
DeclareLocalIdentifier(parameter.Name, parameterType);
|
||||
}
|
||||
catch (CompileException e)
|
||||
{
|
||||
@@ -68,7 +69,6 @@ public class TypeChecker
|
||||
continue;
|
||||
}
|
||||
|
||||
scope.DeclareIdentifier(parameter.Name.Ident, parameterType);
|
||||
parameters.Add(new TypedNodeDefinitionFunc.Param(parameter.Tokens, parameter.Name, parameterType));
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ public class TypeChecker
|
||||
|
||||
private TypedNodeStatementBlock CheckStatementBlock(NodeStatementBlock statement)
|
||||
{
|
||||
using (scope.EnterScope())
|
||||
using (EnterScope())
|
||||
{
|
||||
var statements = statement.Statements.Select(CheckStatement).ToList();
|
||||
return new TypedNodeStatementBlock(statement.Tokens, statements);
|
||||
@@ -137,8 +137,19 @@ public class TypeChecker
|
||||
if (!condition.Type.IsAssignableTo(NubTypeBool.Instance))
|
||||
throw BasicError("Condition part of if statement must be a boolean", condition);
|
||||
|
||||
var thenBlock = CheckStatement(statement.ThenBlock);
|
||||
var elseBlock = statement.ElseBlock == null ? null : CheckStatement(statement.ElseBlock);
|
||||
TypedNodeStatement thenBlock;
|
||||
|
||||
using (EnterScope())
|
||||
{
|
||||
thenBlock = CheckStatement(statement.ThenBlock);
|
||||
}
|
||||
|
||||
TypedNodeStatement? elseBlock;
|
||||
|
||||
using (EnterScope())
|
||||
{
|
||||
elseBlock = statement.ElseBlock == null ? null : CheckStatement(statement.ElseBlock);
|
||||
}
|
||||
|
||||
return new TypedNodeStatementIf(statement.Tokens, condition, thenBlock, elseBlock);
|
||||
}
|
||||
@@ -175,7 +186,7 @@ public class TypeChecker
|
||||
|
||||
type ??= value.Type;
|
||||
|
||||
scope.DeclareIdentifier(statement.Name.Ident, type);
|
||||
DeclareLocalIdentifier(statement.Name, type);
|
||||
|
||||
return new TypedNodeStatementVariableDeclaration(statement.Tokens, statement.Name, type, value);
|
||||
}
|
||||
@@ -186,10 +197,12 @@ public class TypeChecker
|
||||
if (!condition.Type.IsAssignableTo(NubTypeBool.Instance))
|
||||
throw BasicError("Condition part of if statement must be a boolean", condition);
|
||||
|
||||
using (EnterScope())
|
||||
{
|
||||
var body = CheckStatement(statement.Body);
|
||||
|
||||
return new TypedNodeStatementWhile(statement.Tokens, condition, body);
|
||||
}
|
||||
}
|
||||
|
||||
private TypedNodeStatementMatch CheckStatementMatch(NodeStatementMatch statement)
|
||||
{
|
||||
@@ -214,14 +227,14 @@ public class TypeChecker
|
||||
|
||||
uncoveredCases.Remove(@case.Variant.Ident);
|
||||
|
||||
using (scope.EnterScope())
|
||||
using (EnterScope())
|
||||
{
|
||||
if (@case.VariableName != null)
|
||||
{
|
||||
if (variant.Type is null)
|
||||
throw BasicError("Cannot capture variable for enum variant without type", @case.VariableName);
|
||||
|
||||
scope.DeclareIdentifier(@case.VariableName.Ident, variant.Type);
|
||||
DeclareLocalIdentifier(@case.VariableName, variant.Type);
|
||||
}
|
||||
|
||||
var body = CheckStatement(@case.Body);
|
||||
@@ -416,14 +429,14 @@ public class TypeChecker
|
||||
{
|
||||
if (expression.Sections.Count == 1)
|
||||
{
|
||||
var name = expression.Sections[0].Ident;
|
||||
var name = expression.Sections[0];
|
||||
|
||||
var localType = scope.GetIdentifierType(name);
|
||||
var localType = GetIdentifierType(name.Ident);
|
||||
if (localType is not null)
|
||||
return new TypedNodeExpressionLocalIdent(expression.Tokens, localType, name);
|
||||
return new TypedNodeExpressionLocalIdent(expression.Tokens, localType, name.Ident);
|
||||
|
||||
if (moduleGraph.TryResolveIdentifier(currentModule, name, true, out var ident))
|
||||
return new TypedNodeExpressionGlobalIdent(expression.Tokens, ident.Type, currentModule, name);
|
||||
if (moduleGraph.TryResolveIdentifier(currentModule, name.Ident, true, out var ident))
|
||||
return new TypedNodeExpressionGlobalIdent(expression.Tokens, ident.Type, currentModule, name.Ident);
|
||||
}
|
||||
else if (expression.Sections.Count == 2)
|
||||
{
|
||||
@@ -755,19 +768,13 @@ public class TypeChecker
|
||||
return new CompileException(Diagnostic.Error(message).At(fileName, node).Build());
|
||||
}
|
||||
|
||||
private sealed class Scope
|
||||
public void DeclareLocalIdentifier(TokenIdent name, NubType type)
|
||||
{
|
||||
private readonly Stack<Dictionary<string, NubType>> scopes = new();
|
||||
var existing = GetIdentifierType(name.Ident);
|
||||
if (existing is not null)
|
||||
throw BasicError($"Local identifier '{name.Ident}' is already defined", name);
|
||||
|
||||
public IDisposable EnterScope()
|
||||
{
|
||||
scopes.Push([]);
|
||||
return new ScopeGuard(this);
|
||||
}
|
||||
|
||||
public void DeclareIdentifier(string name, NubType type)
|
||||
{
|
||||
scopes.Peek().Add(name, type);
|
||||
scopes.Peek().Add(name.Ident, type);
|
||||
}
|
||||
|
||||
public NubType? GetIdentifierType(string name)
|
||||
@@ -783,19 +790,24 @@ public class TypeChecker
|
||||
return null;
|
||||
}
|
||||
|
||||
public IDisposable EnterScope()
|
||||
{
|
||||
scopes.Push([]);
|
||||
return new ScopeGuard(this);
|
||||
}
|
||||
|
||||
private void ExitScope()
|
||||
{
|
||||
scopes.Pop();
|
||||
}
|
||||
|
||||
private sealed class ScopeGuard(Scope owner) : IDisposable
|
||||
private sealed class ScopeGuard(TypeChecker owner) : IDisposable
|
||||
{
|
||||
public void Dispose()
|
||||
{
|
||||
owner.ExitScope();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class TypedNode(List<Token> tokens)
|
||||
|
||||
Reference in New Issue
Block a user