WIP: dev #1
@@ -180,7 +180,7 @@ public class ModuleGraph
|
|||||||
|
|
||||||
var astModuleCache = new Dictionary<Ast, Module>();
|
var astModuleCache = new Dictionary<Ast, Module>();
|
||||||
|
|
||||||
// First pass: Register modules from ast
|
// Second pass: Register modules from ast
|
||||||
foreach (var ast in asts)
|
foreach (var ast in asts)
|
||||||
{
|
{
|
||||||
if (!modules.ContainsKey(ast.ModuleName.Ident))
|
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)
|
foreach (var ast in asts)
|
||||||
{
|
{
|
||||||
var module = astModuleCache[ast];
|
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)
|
foreach (var ast in asts)
|
||||||
{
|
{
|
||||||
var module = astModuleCache[ast];
|
var module = astModuleCache[ast];
|
||||||
@@ -219,7 +219,7 @@ public class ModuleGraph
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fourth pass: Register identifiers
|
// Fifth pass: Register identifiers
|
||||||
foreach (var ast in asts)
|
foreach (var ast in asts)
|
||||||
{
|
{
|
||||||
var module = astModuleCache[ast];
|
var module = astModuleCache[ast];
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class TypeChecker
|
|||||||
private readonly string moduleName;
|
private readonly string moduleName;
|
||||||
private readonly NodeDefinitionFunc function;
|
private readonly NodeDefinitionFunc function;
|
||||||
private readonly ModuleGraph moduleGraph;
|
private readonly ModuleGraph moduleGraph;
|
||||||
private readonly Scope scope = new(null);
|
private readonly Scope scope = new();
|
||||||
|
|
||||||
private TypedNodeDefinitionFunc? CheckFunction(out List<Diagnostic> diagnostics)
|
private TypedNodeDefinitionFunc? CheckFunction(out List<Diagnostic> diagnostics)
|
||||||
{
|
{
|
||||||
@@ -30,48 +30,50 @@ public class TypeChecker
|
|||||||
TypedNodeStatement? body = null;
|
TypedNodeStatement? body = null;
|
||||||
NubType? returnType = 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
|
try
|
||||||
{
|
{
|
||||||
parameters.Add(CheckDefinitionFuncParameter(parameter));
|
body = CheckStatement(function.Body);
|
||||||
}
|
}
|
||||||
catch (CompileException e)
|
catch (CompileException e)
|
||||||
{
|
{
|
||||||
diagnostics.Add(e.Diagnostic);
|
diagnostics.Add(e.Diagnostic);
|
||||||
invalidParameter = true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
body = CheckStatement(function.Body);
|
returnType = ResolveType(function.ReturnType);
|
||||||
}
|
}
|
||||||
catch (CompileException e)
|
catch (CompileException e)
|
||||||
{
|
{
|
||||||
diagnostics.Add(e.Diagnostic);
|
diagnostics.Add(e.Diagnostic);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
if (body == null || returnType == null || invalidParameter)
|
||||||
{
|
return null;
|
||||||
returnType = ResolveType(function.ReturnType);
|
|
||||||
|
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)
|
private TypedNodeStatement CheckStatement(NodeStatement node)
|
||||||
@@ -96,7 +98,11 @@ public class TypeChecker
|
|||||||
|
|
||||||
private TypedNodeStatementBlock CheckStatementBlock(NodeStatementBlock statement)
|
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)
|
private TypedNodeStatementFuncCall CheckStatementExpression(NodeStatementExpression statement)
|
||||||
@@ -406,20 +412,45 @@ public class TypeChecker
|
|||||||
return customType;
|
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)
|
public void DeclareIdentifier(string name, NubType type)
|
||||||
{
|
{
|
||||||
identifiers.Add(name, type);
|
scopes.Peek().Add(name, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public NubType? GetIdentifierType(string name)
|
public NubType? GetIdentifierType(string name)
|
||||||
{
|
{
|
||||||
return identifiers.TryGetValue(name, out var type)
|
foreach (var scope in scopes)
|
||||||
? type
|
{
|
||||||
: parent?.GetIdentifierType(name);
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user