Add most of the type checkers
This commit is contained in:
@@ -38,7 +38,7 @@ public record UnaryExpressionSyntax(IEnumerable<Token> Tokens, UnaryOperatorSynt
|
||||
|
||||
public record FuncCallSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Expression, List<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens);
|
||||
|
||||
public record DotFuncCallSyntax(IEnumerable<Token> Tokens, string Name, ExpressionSyntax ThisParameter, List<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens);
|
||||
public record DotFuncCallSyntax(IEnumerable<Token> Tokens, string Name, ExpressionSyntax Target, List<ExpressionSyntax> Parameters) : ExpressionSyntax(Tokens);
|
||||
|
||||
public record LocalIdentifierSyntax(IEnumerable<Token> Tokens, string Name) : ExpressionSyntax(Tokens);
|
||||
|
||||
@@ -48,7 +48,7 @@ public record ArrayInitializerSyntax(IEnumerable<Token> Tokens, ExpressionSyntax
|
||||
|
||||
public record ArrayIndexAccessSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Target, ExpressionSyntax Index) : ExpressionSyntax(Tokens);
|
||||
|
||||
public record AddressOfSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens);
|
||||
public record AddressOfSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
|
||||
|
||||
public record LiteralSyntax(IEnumerable<Token> Tokens, string Value, LiteralKind Kind) : ExpressionSyntax(Tokens);
|
||||
|
||||
@@ -56,4 +56,4 @@ public record StructFieldAccessSyntax(IEnumerable<Token> Tokens, ExpressionSynta
|
||||
|
||||
public record StructInitializerSyntax(IEnumerable<Token> Tokens, Optional<TypeSyntax> StructType, Dictionary<string, ExpressionSyntax> Initializers) : ExpressionSyntax(Tokens);
|
||||
|
||||
public record DereferenceSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Expression) : ExpressionSyntax(Tokens);
|
||||
public record DereferenceSyntax(IEnumerable<Token> Tokens, ExpressionSyntax Target) : ExpressionSyntax(Tokens);
|
||||
@@ -66,6 +66,20 @@ public sealed class TypeChecker
|
||||
|
||||
private StructNode CheckStructDefinition(StructSyntax node)
|
||||
{
|
||||
var fieldTypes = node.Fields
|
||||
.Select(x => new StructTypeField(x.Name, ResolveType(x.Type), x.Value.HasValue))
|
||||
.ToList();
|
||||
|
||||
var functionTypes = new List<StructTypeFunc>();
|
||||
foreach (var function in node.Functions)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
var type = new StructTypeNode(_syntaxTree.Metadata.ModuleName, node.Name, fieldTypes, functionTypes);
|
||||
|
||||
var fields = new List<StructFieldNode>();
|
||||
foreach (var field in node.Fields)
|
||||
{
|
||||
@@ -82,7 +96,8 @@ public sealed class TypeChecker
|
||||
foreach (var function in node.Functions)
|
||||
{
|
||||
var scope = new Scope();
|
||||
// todo(nub31): Add this parameter
|
||||
scope.Declare(new Identifier("this", type, IdentifierKind.FunctionParameter));
|
||||
|
||||
foreach (var parameter in function.Signature.Parameters)
|
||||
{
|
||||
scope.Declare(new Identifier(parameter.Name, ResolveType(parameter.Type), IdentifierKind.FunctionParameter));
|
||||
@@ -94,20 +109,6 @@ public sealed class TypeChecker
|
||||
functions.Add(new StructFuncNode(function.Name, CheckFuncSignature(function.Signature), body));
|
||||
}
|
||||
|
||||
var fieldTypes = node.Fields
|
||||
.Select(x => new StructTypeField(x.Name, ResolveType(x.Type), x.Value.HasValue))
|
||||
.ToList();
|
||||
|
||||
var functionTypes = new List<StructTypeFunc>();
|
||||
foreach (var function in node.Functions)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
var type = new StructTypeNode(_syntaxTree.Metadata.ModuleName, node.Name, fieldTypes, functionTypes);
|
||||
|
||||
return new StructNode(type, _syntaxTree.Metadata.ModuleName, node.Name, fields, functions);
|
||||
}
|
||||
|
||||
@@ -146,23 +147,38 @@ public sealed class TypeChecker
|
||||
};
|
||||
}
|
||||
|
||||
private StatementNode CheckAssignment(AssignmentSyntax statement)
|
||||
private AssignmentNode CheckAssignment(AssignmentSyntax statement)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var target = CheckExpression(statement.Target);
|
||||
if (target is not LValueExpressionNode lValue)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error("Cannot assign to an rvalue").At(statement).Build());
|
||||
}
|
||||
|
||||
var value = CheckExpression(statement.Value, lValue.Type);
|
||||
return new AssignmentNode(lValue, value);
|
||||
}
|
||||
|
||||
private IfNode CheckIf(IfSyntax statement)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var condition = CheckExpression(statement.Condition, new BoolTypeNode());
|
||||
var body = CheckBlock(statement.Body);
|
||||
var elseStatement = Optional.Empty<Variant<IfNode, BlockNode>>();
|
||||
if (statement.Else.TryGetValue(out var elseSyntax))
|
||||
{
|
||||
elseStatement = elseSyntax.Match<Variant<IfNode, BlockNode>>(elif => CheckIf(elif), el => CheckBlock(el));
|
||||
}
|
||||
|
||||
return new IfNode(condition, body, elseStatement);
|
||||
}
|
||||
|
||||
private ReturnNode CheckReturn(ReturnSyntax statement)
|
||||
{
|
||||
var value = Optional.Empty<ExpressionNode>();
|
||||
|
||||
if (statement.Value.HasValue)
|
||||
if (statement.Value.TryGetValue(out var valueExpression))
|
||||
{
|
||||
value = CheckExpression(statement.Value.Value, _funcReturnTypes.Peek());
|
||||
value = CheckExpression(valueExpression, _funcReturnTypes.Peek());
|
||||
}
|
||||
|
||||
return new ReturnNode(value);
|
||||
@@ -201,7 +217,9 @@ public sealed class TypeChecker
|
||||
|
||||
private WhileNode CheckWhile(WhileSyntax statement)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var condition = CheckExpression(statement.Condition, new BoolTypeNode());
|
||||
var body = CheckBlock(statement.Body);
|
||||
return new WhileNode(condition, body);
|
||||
}
|
||||
|
||||
private FuncSignatureNode CheckFuncSignature(FuncSignatureSyntax statement)
|
||||
@@ -223,6 +241,7 @@ public sealed class TypeChecker
|
||||
ArrayIndexAccessSyntax expression => CheckArrayIndexAccess(expression),
|
||||
ArrayInitializerSyntax expression => CheckArrayInitializer(expression),
|
||||
BinaryExpressionSyntax expression => CheckBinaryExpression(expression),
|
||||
UnaryExpressionSyntax expression => CheckUnaryExpression(expression),
|
||||
DereferenceSyntax expression => CheckDereference(expression),
|
||||
DotFuncCallSyntax expression => CheckDotFuncCall(expression),
|
||||
FuncCallSyntax expression => CheckFuncCall(expression),
|
||||
@@ -231,7 +250,6 @@ public sealed class TypeChecker
|
||||
LiteralSyntax expression => CheckLiteral(expression, expectedType),
|
||||
StructFieldAccessSyntax expression => CheckStructFieldAccess(expression),
|
||||
StructInitializerSyntax expression => CheckStructInitializer(expression, expectedType),
|
||||
UnaryExpressionSyntax expression => CheckUnaryExpression(expression),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
||||
};
|
||||
|
||||
@@ -261,27 +279,171 @@ public sealed class TypeChecker
|
||||
|
||||
private AddressOfNode CheckAddressOf(AddressOfSyntax expression)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var target = CheckExpression(expression.Target);
|
||||
if (target is not LValueExpressionNode lvalue)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error("Cannot take address of an rvalue").Build());
|
||||
}
|
||||
|
||||
var type = new PointerTypeNode(target.Type);
|
||||
return new AddressOfNode(type, lvalue);
|
||||
}
|
||||
|
||||
private ArrayIndexAccessNode CheckArrayIndexAccess(ArrayIndexAccessSyntax expression)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var index = CheckExpression(expression.Index, new IntTypeNode(false, 64));
|
||||
var target = CheckExpression(expression.Target);
|
||||
if (target.Type is not ArrayTypeNode arrayType)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error($"Cannot use array indexer on type {target.Type}").At(expression).Build());
|
||||
}
|
||||
|
||||
return new ArrayIndexAccessNode(arrayType.ElementType, target, index);
|
||||
}
|
||||
|
||||
private ArrayInitializerNode CheckArrayInitializer(ArrayInitializerSyntax expression)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var elementType = ResolveType(expression.ElementType);
|
||||
var type = new ArrayTypeNode(elementType);
|
||||
var capacity = CheckExpression(expression.Capacity);
|
||||
return new ArrayInitializerNode(type, capacity, elementType);
|
||||
}
|
||||
|
||||
private BinaryExpressionNode CheckBinaryExpression(BinaryExpressionSyntax expression)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var op = expression.Operator switch
|
||||
{
|
||||
BinaryOperatorSyntax.Equal => BinaryOperator.Equal,
|
||||
BinaryOperatorSyntax.NotEqual => BinaryOperator.NotEqual,
|
||||
BinaryOperatorSyntax.GreaterThan => BinaryOperator.GreaterThan,
|
||||
BinaryOperatorSyntax.GreaterThanOrEqual => BinaryOperator.GreaterThanOrEqual,
|
||||
BinaryOperatorSyntax.LessThan => BinaryOperator.LessThan,
|
||||
BinaryOperatorSyntax.LessThanOrEqual => BinaryOperator.LessThanOrEqual,
|
||||
BinaryOperatorSyntax.LogicalAnd => BinaryOperator.LogicalAnd,
|
||||
BinaryOperatorSyntax.LogicalOr => BinaryOperator.LogicalOr,
|
||||
BinaryOperatorSyntax.Plus => BinaryOperator.Plus,
|
||||
BinaryOperatorSyntax.Minus => BinaryOperator.Minus,
|
||||
BinaryOperatorSyntax.Multiply => BinaryOperator.Multiply,
|
||||
BinaryOperatorSyntax.Divide => BinaryOperator.Divide,
|
||||
BinaryOperatorSyntax.Modulo => BinaryOperator.Modulo,
|
||||
BinaryOperatorSyntax.LeftShift => BinaryOperator.LeftShift,
|
||||
BinaryOperatorSyntax.RightShift => BinaryOperator.RightShift,
|
||||
BinaryOperatorSyntax.BitwiseAnd => BinaryOperator.BitwiseAnd,
|
||||
BinaryOperatorSyntax.BitwiseXor => BinaryOperator.BitwiseXor,
|
||||
BinaryOperatorSyntax.BitwiseOr => BinaryOperator.BitwiseOr,
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
switch (expression.Operator)
|
||||
{
|
||||
case BinaryOperatorSyntax.Equal:
|
||||
case BinaryOperatorSyntax.NotEqual:
|
||||
case BinaryOperatorSyntax.GreaterThan:
|
||||
case BinaryOperatorSyntax.GreaterThanOrEqual:
|
||||
case BinaryOperatorSyntax.LessThan:
|
||||
case BinaryOperatorSyntax.LessThanOrEqual:
|
||||
case BinaryOperatorSyntax.LogicalAnd:
|
||||
case BinaryOperatorSyntax.LogicalOr:
|
||||
{
|
||||
var left = CheckExpression(expression.Left);
|
||||
if (left.Type is not IntTypeNode or FloatTypeNode)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error("Logical operators must must be used with int or float types").At(expression.Left).Build());
|
||||
}
|
||||
|
||||
var right = CheckExpression(expression.Right, left.Type);
|
||||
|
||||
return new BinaryExpressionNode(new BoolTypeNode(), left, op, right);
|
||||
}
|
||||
case BinaryOperatorSyntax.Plus:
|
||||
{
|
||||
var left = CheckExpression(expression.Left);
|
||||
if (left.Type is IntTypeNode or FloatTypeNode or StringTypeNode or StringTypeNode)
|
||||
{
|
||||
var right = CheckExpression(expression.Right, left.Type);
|
||||
return new BinaryExpressionNode(left.Type, left, op, right);
|
||||
}
|
||||
|
||||
throw new TypeCheckerException(Diagnostic.Error("The plus operator must be used with int, float or string types").At(expression.Left).Build());
|
||||
}
|
||||
case BinaryOperatorSyntax.Minus:
|
||||
case BinaryOperatorSyntax.Multiply:
|
||||
case BinaryOperatorSyntax.Divide:
|
||||
case BinaryOperatorSyntax.Modulo:
|
||||
{
|
||||
var left = CheckExpression(expression.Left);
|
||||
if (left.Type is not IntTypeNode or FloatTypeNode)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error("Math operators must be used with int or float types").At(expression.Left).Build());
|
||||
}
|
||||
|
||||
var right = CheckExpression(expression.Right, left.Type);
|
||||
|
||||
return new BinaryExpressionNode(left.Type, left, op, right);
|
||||
}
|
||||
case BinaryOperatorSyntax.LeftShift:
|
||||
case BinaryOperatorSyntax.RightShift:
|
||||
case BinaryOperatorSyntax.BitwiseAnd:
|
||||
case BinaryOperatorSyntax.BitwiseXor:
|
||||
case BinaryOperatorSyntax.BitwiseOr:
|
||||
{
|
||||
var left = CheckExpression(expression.Left);
|
||||
if (left.Type is not IntTypeNode)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error("Bitwise operators must be used with int types").At(expression.Left).Build());
|
||||
}
|
||||
|
||||
var right = CheckExpression(expression.Right, left.Type);
|
||||
|
||||
return new BinaryExpressionNode(left.Type, left, op, right);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private UnaryExpressionNode CheckUnaryExpression(UnaryExpressionSyntax expression)
|
||||
{
|
||||
switch (expression.Operator)
|
||||
{
|
||||
case UnaryOperatorSyntax.Negate:
|
||||
{
|
||||
var operand = CheckExpression(expression.Operand);
|
||||
if (operand.Type is not IntTypeNode { Signed: false } or FloatTypeNode)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error("Negation operator must be used with signed integer or float types").Build());
|
||||
}
|
||||
|
||||
return new UnaryExpressionNode(operand.Type, UnaryOperator.Negate, operand);
|
||||
}
|
||||
case UnaryOperatorSyntax.Invert:
|
||||
{
|
||||
var operand = CheckExpression(expression.Operand);
|
||||
if (operand.Type is not BoolTypeNode)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error("Invert operator must be used with booleans").Build());
|
||||
}
|
||||
|
||||
return new UnaryExpressionNode(operand.Type, UnaryOperator.Invert, operand);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DereferenceNode CheckDereference(DereferenceSyntax expression)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
var target = CheckExpression(expression.Target);
|
||||
if (target.Type is not PointerTypeNode pointerType)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error($"Cannot dereference non-pointer type {target.Type}").At(expression).Build());
|
||||
}
|
||||
|
||||
return new DereferenceNode(pointerType.BaseType, target);
|
||||
}
|
||||
|
||||
private FuncCallNode CheckFuncCall(FuncCallSyntax expression)
|
||||
@@ -315,9 +477,37 @@ public sealed class TypeChecker
|
||||
return new FuncCallNode(funcType.ReturnType, accessor, parameters);
|
||||
}
|
||||
|
||||
private ExpressionNode CheckDotFuncCall(DotFuncCallSyntax expression)
|
||||
private StructFuncCallNode CheckDotFuncCall(DotFuncCallSyntax expression)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
// todo(nub31): When adding interfaces, also support other types than structs
|
||||
var target = CheckExpression(expression.Target);
|
||||
if (target.Type is StructTypeNode structType)
|
||||
{
|
||||
var function = structType.Functions.FirstOrDefault(x => x.Name == expression.Name);
|
||||
if (function == null)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error($"Function {expression.Name} not found on struct {structType}").At(expression).Build());
|
||||
}
|
||||
|
||||
var parameters = new List<ExpressionNode>();
|
||||
for (var i = 0; i < expression.Parameters.Count; i++)
|
||||
{
|
||||
var parameter = expression.Parameters[i];
|
||||
var expectedType = function.Type.Parameters[i];
|
||||
|
||||
var parameterExpression = CheckExpression(parameter, expectedType);
|
||||
if (parameterExpression.Type != expectedType)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error($"Parameter {i + 1} does not match the type {expectedType} for function {function}").At(parameter).Build());
|
||||
}
|
||||
|
||||
parameters.Add(parameterExpression);
|
||||
}
|
||||
|
||||
return new StructFuncCallNode(function.Type.ReturnType, expression.Name, structType, target, parameters);
|
||||
}
|
||||
|
||||
throw new TypeCheckerException(Diagnostic.Error($"No function {expression.Name} exists on type {target.Type}").Build());
|
||||
}
|
||||
|
||||
private ExpressionNode CheckLocalIdentifier(LocalIdentifierSyntax expression)
|
||||
@@ -479,11 +669,6 @@ public sealed class TypeChecker
|
||||
return new StructInitializerNode(structType, initializers);
|
||||
}
|
||||
|
||||
private UnaryExpressionNode CheckUnaryExpression(UnaryExpressionSyntax expression)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private BlockNode CheckBlock(BlockSyntax node, Scope? scope = null)
|
||||
{
|
||||
var statements = new List<StatementNode>();
|
||||
@@ -555,7 +740,12 @@ public sealed class TypeChecker
|
||||
var fields = structType.Fields.Select(x => new StructTypeField(x.Name, ResolveType(x.Type), x.HasDefaultValue)).ToList();
|
||||
result.Fields.AddRange(fields);
|
||||
|
||||
// todo(nub31): Function implementations
|
||||
foreach (var function in structType.Functions)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
_referencedStructTypes.Add(result);
|
||||
return result;
|
||||
|
||||
Reference in New Issue
Block a user