defer and struct hooks
This commit is contained in:
@@ -72,7 +72,7 @@ public record StructFieldAccessNode(TypeNode Type, StructTypeNode StructType, Ex
|
||||
|
||||
public record StructInitializerNode(StructTypeNode StructType, Dictionary<string, ExpressionNode> Initializers) : RValueExpressionNode(StructType);
|
||||
|
||||
public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : RValueExpressionNode(Type);
|
||||
public record DereferenceNode(TypeNode Type, ExpressionNode Expression) : LValueExpressionNode(Type);
|
||||
|
||||
public record ConvertIntNode(TypeNode Type, ExpressionNode Value, IntTypeNode ValueType, IntTypeNode TargetType) : RValueExpressionNode(Type);
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
namespace NubLang.TypeChecking.Node;
|
||||
|
||||
public abstract record Node;
|
||||
|
||||
public record BlockNode(List<StatementNode> Statements) : Node;
|
||||
public abstract record Node;
|
||||
@@ -2,9 +2,13 @@
|
||||
|
||||
public abstract record StatementNode : Node;
|
||||
|
||||
public abstract record TerminalStatementNode : StatementNode;
|
||||
|
||||
public record BlockNode(List<StatementNode> Statements) : StatementNode;
|
||||
|
||||
public record StatementExpressionNode(ExpressionNode Expression) : StatementNode;
|
||||
|
||||
public record ReturnNode(Optional<ExpressionNode> Value) : StatementNode;
|
||||
public record ReturnNode(Optional<ExpressionNode> Value) : TerminalStatementNode;
|
||||
|
||||
public record AssignmentNode(LValueExpressionNode Target, ExpressionNode Value) : StatementNode;
|
||||
|
||||
@@ -12,9 +16,11 @@ public record IfNode(ExpressionNode Condition, BlockNode Body, Optional<Variant<
|
||||
|
||||
public record VariableDeclarationNode(string Name, Optional<ExpressionNode> Assignment, TypeNode Type) : StatementNode;
|
||||
|
||||
public record ContinueNode : StatementNode;
|
||||
public record ContinueNode : TerminalStatementNode;
|
||||
|
||||
public record BreakNode : StatementNode;
|
||||
public record BreakNode : TerminalStatementNode;
|
||||
|
||||
public record DeferNode(StatementNode Statement) : StatementNode;
|
||||
|
||||
public record WhileNode(ExpressionNode Condition, BlockNode Body) : StatementNode;
|
||||
|
||||
|
||||
@@ -119,9 +119,10 @@ public class StructTypeField(string name, TypeNode type, bool hasDefaultValue)
|
||||
public bool HasDefaultValue { get; } = hasDefaultValue;
|
||||
}
|
||||
|
||||
public class StructTypeFunc(string name, FuncTypeNode type)
|
||||
public class StructTypeFunc(string name, string? hook, FuncTypeNode type)
|
||||
{
|
||||
public string Name { get; } = name;
|
||||
public string? Hook { get; set; } = hook;
|
||||
public FuncTypeNode Type { get; } = type;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ public sealed class TypeChecker
|
||||
{
|
||||
var parameters = function.Signature.Parameters.Select(x => ResolveType(x.Type)).ToList();
|
||||
var funcType = new FuncTypeNode(parameters, ResolveType(function.Signature.ReturnType));
|
||||
functionTypes.Add(new StructTypeFunc(function.Name, funcType));
|
||||
functionTypes.Add(new StructTypeFunc(function.Name, function.Hook, funcType));
|
||||
}
|
||||
|
||||
var type = new StructTypeNode(_syntaxTree.Metadata.ModuleName, node.Name, fieldTypes, functionTypes);
|
||||
@@ -127,10 +127,19 @@ public sealed class TypeChecker
|
||||
|
||||
body = CheckBlock(node.Body, scope);
|
||||
|
||||
// Insert implicit return for void functions
|
||||
if (signature.ReturnType is VoidTypeNode && body.Statements.LastOrDefault() is not ReturnNode)
|
||||
if (!AlwaysReturns(body))
|
||||
{
|
||||
body.Statements.Add(new ReturnNode(Optional<ExpressionNode>.Empty()));
|
||||
if (signature.ReturnType is VoidTypeNode)
|
||||
{
|
||||
body.Statements.Add(new ReturnNode(Optional<ExpressionNode>.Empty()));
|
||||
}
|
||||
else
|
||||
{
|
||||
Diagnostics.Add(Diagnostic
|
||||
.Error("Not all code paths return a value")
|
||||
.At(node.Body.Tokens.LastOrDefault())
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
||||
_funcReturnTypes.Pop();
|
||||
@@ -150,6 +159,7 @@ public sealed class TypeChecker
|
||||
ReturnSyntax statement => CheckReturn(statement),
|
||||
StatementExpressionSyntax statement => CheckStatementExpression(statement),
|
||||
VariableDeclarationSyntax statement => CheckVariableDeclaration(statement),
|
||||
DeferSyntax statement => CheckDefer(statement),
|
||||
WhileSyntax statement => CheckWhile(statement),
|
||||
ForSyntax statement => CheckFor(statement),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
||||
@@ -224,6 +234,11 @@ public sealed class TypeChecker
|
||||
return new VariableDeclarationNode(statement.Name, Optional.OfNullable(assignmentNode), type);
|
||||
}
|
||||
|
||||
private DeferNode CheckDefer(DeferSyntax statement)
|
||||
{
|
||||
return new DeferNode(CheckStatement(statement.Statement));
|
||||
}
|
||||
|
||||
private WhileNode CheckWhile(WhileSyntax statement)
|
||||
{
|
||||
var condition = CheckExpression(statement.Condition, new BoolTypeNode());
|
||||
@@ -734,8 +749,8 @@ public sealed class TypeChecker
|
||||
|
||||
if (missingFields.Length != 0)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Fields {string.Join(", ", missingFields)} are not initialized")
|
||||
Diagnostics.Add(Diagnostic
|
||||
.Warning($"Fields {string.Join(", ", missingFields)} are not initialized")
|
||||
.At(expression)
|
||||
.Build());
|
||||
}
|
||||
@@ -759,7 +774,7 @@ public sealed class TypeChecker
|
||||
if (reachable)
|
||||
{
|
||||
statements.Add(checkedStatement);
|
||||
if (checkedStatement is ReturnNode or BreakNode or ContinueNode)
|
||||
if (checkedStatement is TerminalStatementNode)
|
||||
{
|
||||
reachable = false;
|
||||
}
|
||||
@@ -779,6 +794,17 @@ public sealed class TypeChecker
|
||||
return new BlockNode(statements);
|
||||
}
|
||||
|
||||
private bool AlwaysReturns(StatementNode statement)
|
||||
{
|
||||
return statement switch
|
||||
{
|
||||
ReturnNode => true,
|
||||
BlockNode block => block.Statements.Count != 0 && AlwaysReturns(block.Statements.Last()),
|
||||
IfNode ifNode => AlwaysReturns(ifNode.Body) && ifNode.Else.TryGetValue(out var elseStatement) ? elseStatement.Match(AlwaysReturns, AlwaysReturns) : true,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
|
||||
private TypeNode ResolveType(TypeSyntax type)
|
||||
{
|
||||
return type switch
|
||||
@@ -838,7 +864,7 @@ public sealed class TypeChecker
|
||||
{
|
||||
var parameters = function.Parameters.Select(x => ResolveType(x.Type)).ToList();
|
||||
var type = new FuncTypeNode(parameters, ResolveType(function.ReturnType));
|
||||
result.Functions.Add(new StructTypeFunc(function.Name, type));
|
||||
result.Functions.Add(new StructTypeFunc(function.Name, function.Hook, type));
|
||||
}
|
||||
|
||||
ReferencedStructTypes.Add(result);
|
||||
|
||||
Reference in New Issue
Block a user