Big type inference improvements
This commit is contained in:
@@ -80,17 +80,29 @@ public abstract record LValueExpressionNode(List<Token> Tokens, NubType Type) :
|
||||
|
||||
public abstract record RValueExpressionNode(List<Token> Tokens, NubType Type) : ExpressionNode(Tokens, Type);
|
||||
|
||||
public record StringLiteralNode(List<Token> Tokens, NubType Type, string Value) : RValueExpressionNode(Tokens, Type);
|
||||
public record StringLiteralNode(List<Token> Tokens, string Value) : RValueExpressionNode(Tokens, new NubStringType());
|
||||
|
||||
public record CStringLiteralNode(List<Token> Tokens, NubType Type, string Value) : RValueExpressionNode(Tokens, Type);
|
||||
public record CStringLiteralNode(List<Token> Tokens, string Value) : RValueExpressionNode(Tokens, new NubCStringType());
|
||||
|
||||
public record IntLiteralNode(List<Token> Tokens, NubType Type, long Value) : RValueExpressionNode(Tokens, Type);
|
||||
public record I8LiteralNode(List<Token> Tokens, sbyte Value) : RValueExpressionNode(Tokens, new NubIntType(true, 8));
|
||||
|
||||
public record UIntLiteralNode(List<Token> Tokens, NubType Type, ulong Value) : RValueExpressionNode(Tokens, Type);
|
||||
public record I16LiteralNode(List<Token> Tokens, short Value) : RValueExpressionNode(Tokens, new NubIntType(true, 16));
|
||||
|
||||
public record Float32LiteralNode(List<Token> Tokens, NubType Type, float Value) : RValueExpressionNode(Tokens, Type);
|
||||
public record I32LiteralNode(List<Token> Tokens, int Value) : RValueExpressionNode(Tokens, new NubIntType(true, 32));
|
||||
|
||||
public record Float64LiteralNode(List<Token> Tokens, NubType Type, double Value) : RValueExpressionNode(Tokens, Type);
|
||||
public record I64LiteralNode(List<Token> Tokens, long Value) : RValueExpressionNode(Tokens, new NubIntType(true, 64));
|
||||
|
||||
public record U8LiteralNode(List<Token> Tokens, byte Value) : RValueExpressionNode(Tokens, new NubIntType(false, 8));
|
||||
|
||||
public record U16LiteralNode(List<Token> Tokens, ushort Value) : RValueExpressionNode(Tokens, new NubIntType(false, 16));
|
||||
|
||||
public record U32LiteralNode(List<Token> Tokens, uint Value) : RValueExpressionNode(Tokens, new NubIntType(false, 32));
|
||||
|
||||
public record U64LiteralNode(List<Token> Tokens, ulong Value) : RValueExpressionNode(Tokens, new NubIntType(false, 64));
|
||||
|
||||
public record Float32LiteralNode(List<Token> Tokens, float Value) : RValueExpressionNode(Tokens, new NubFloatType(32));
|
||||
|
||||
public record Float64LiteralNode(List<Token> Tokens, double Value) : RValueExpressionNode(Tokens, new NubFloatType(64));
|
||||
|
||||
public record BoolLiteralNode(List<Token> Tokens, NubType Type, bool Value) : RValueExpressionNode(Tokens, Type);
|
||||
|
||||
@@ -114,13 +126,13 @@ public record AddressOfNode(List<Token> Tokens, NubType Type, LValueExpressionNo
|
||||
|
||||
public record StructFieldAccessNode(List<Token> Tokens, NubType Type, ExpressionNode Target, string Field) : LValueExpressionNode(Tokens, Type);
|
||||
|
||||
public record StructInitializerNode(List<Token> Tokens, NubStructType StructType, Dictionary<string, ExpressionNode> Initializers) : RValueExpressionNode(Tokens, StructType);
|
||||
public record StructInitializerNode(List<Token> Tokens, NubType Type, Dictionary<string, ExpressionNode> Initializers) : RValueExpressionNode(Tokens, Type);
|
||||
|
||||
public record DereferenceNode(List<Token> Tokens, NubType Type, ExpressionNode Target) : LValueExpressionNode(Tokens, Type);
|
||||
|
||||
public record ConvertIntNode(List<Token> Tokens, NubType Type, ExpressionNode Value, NubIntType ValueType, NubIntType TargetType) : RValueExpressionNode(Tokens, Type);
|
||||
public record ConvertIntNode(List<Token> Tokens, ExpressionNode Value, int StartWidth, int TargetWidth, bool StartSignedness, bool TargetSignedness) : RValueExpressionNode(Tokens, new NubIntType(TargetSignedness, TargetWidth));
|
||||
|
||||
public record ConvertFloatNode(List<Token> Tokens, NubType Type, ExpressionNode Value, NubFloatType ValueType, NubFloatType TargetType) : RValueExpressionNode(Tokens, Type);
|
||||
public record ConvertFloatNode(List<Token> Tokens, ExpressionNode Value, int StartWidth, int TargetWidth) : RValueExpressionNode(Tokens, new NubFloatType(TargetWidth));
|
||||
|
||||
public record ConvertStringToCStringNode(List<Token> Tokens, ExpressionNode Value) : RValueExpressionNode(Tokens, new NubCStringType());
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ public sealed class TypeChecker
|
||||
private readonly Dictionary<string, Module> _importedModules;
|
||||
|
||||
private readonly Stack<Scope> _scopes = [];
|
||||
private readonly Stack<NubType> _funcReturnTypes = [];
|
||||
private readonly Dictionary<(string Module, string Name), NubType> _typeCache = new();
|
||||
private readonly HashSet<(string Module, string Name)> _resolvingTypes = [];
|
||||
|
||||
@@ -29,7 +28,6 @@ public sealed class TypeChecker
|
||||
public CompilationUnit Check()
|
||||
{
|
||||
_scopes.Clear();
|
||||
_funcReturnTypes.Clear();
|
||||
_typeCache.Clear();
|
||||
_resolvingTypes.Clear();
|
||||
|
||||
@@ -117,26 +115,26 @@ public sealed class TypeChecker
|
||||
BlockNode? body = null;
|
||||
if (node.Body != null)
|
||||
{
|
||||
_funcReturnTypes.Push(prototype.ReturnType);
|
||||
|
||||
body = CheckBlock(node.Body);
|
||||
|
||||
if (!AlwaysReturns(body))
|
||||
using (BeginScope())
|
||||
{
|
||||
if (prototype.ReturnType is NubVoidType)
|
||||
CurrentScope.SetReturnType(prototype.ReturnType);
|
||||
body = CheckBlock(node.Body);
|
||||
|
||||
if (!AlwaysReturns(body))
|
||||
{
|
||||
body.Statements.Add(new ReturnNode(node.Tokens.Skip(node.Tokens.Count - 1).ToList(), null));
|
||||
}
|
||||
else
|
||||
{
|
||||
Diagnostics.Add(Diagnostic
|
||||
.Error("Not all code paths return a value")
|
||||
.At(node.Body)
|
||||
.Build());
|
||||
if (prototype.ReturnType is NubVoidType)
|
||||
{
|
||||
body.Statements.Add(new ReturnNode(node.Tokens.Skip(node.Tokens.Count - 1).ToList(), null));
|
||||
}
|
||||
else
|
||||
{
|
||||
Diagnostics.Add(Diagnostic
|
||||
.Error("Not all code paths return a value")
|
||||
.At(node.Body)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_funcReturnTypes.Pop();
|
||||
}
|
||||
|
||||
return new FuncNode(node.Tokens, prototype, body);
|
||||
@@ -151,12 +149,21 @@ public sealed class TypeChecker
|
||||
}
|
||||
|
||||
var value = CheckExpression(statement.Value, lValue.Type);
|
||||
|
||||
if (value.Type != lValue.Type)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Cannot assign {value.Type} to {lValue.Type}")
|
||||
.At(statement.Value)
|
||||
.Build());
|
||||
}
|
||||
|
||||
return new AssignmentNode(statement.Tokens, lValue, value);
|
||||
}
|
||||
|
||||
private IfNode CheckIf(IfSyntax statement)
|
||||
{
|
||||
var condition = CheckExpression(statement.Condition, new NubBoolType());
|
||||
var condition = CheckExpression(statement.Condition);
|
||||
var body = CheckBlock(statement.Body);
|
||||
Variant<IfNode, BlockNode>? elseStatement = null;
|
||||
if (statement.Else.HasValue)
|
||||
@@ -173,7 +180,8 @@ public sealed class TypeChecker
|
||||
|
||||
if (statement.Value != null)
|
||||
{
|
||||
value = CheckExpression(statement.Value, _funcReturnTypes.Peek());
|
||||
var expectedReturnType = CurrentScope.GetReturnType();
|
||||
value = CheckExpression(statement.Value, expectedReturnType);
|
||||
}
|
||||
|
||||
return new ReturnNode(statement.Tokens, value);
|
||||
@@ -203,12 +211,26 @@ public sealed class TypeChecker
|
||||
if (statement.Assignment != null)
|
||||
{
|
||||
assignmentNode = CheckExpression(statement.Assignment, type);
|
||||
type ??= assignmentNode.Type;
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
type = assignmentNode.Type;
|
||||
}
|
||||
else if (assignmentNode.Type != type)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Cannot assign {assignmentNode.Type} to variable of type {type}")
|
||||
.At(statement.Assignment)
|
||||
.Build());
|
||||
}
|
||||
}
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error($"Cannot infer type of variable {statement.Name}").At(statement).Build());
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Cannot infer type of variable {statement.Name}")
|
||||
.At(statement)
|
||||
.Build());
|
||||
}
|
||||
|
||||
CurrentScope.DeclareVariable(new Variable(statement.Name, type));
|
||||
@@ -218,7 +240,7 @@ public sealed class TypeChecker
|
||||
|
||||
private WhileNode CheckWhile(WhileSyntax statement)
|
||||
{
|
||||
var condition = CheckExpression(statement.Condition, new NubBoolType());
|
||||
var condition = CheckExpression(statement.Condition);
|
||||
var body = CheckBlock(statement.Body);
|
||||
return new WhileNode(statement.Tokens, condition, body);
|
||||
}
|
||||
@@ -236,64 +258,32 @@ public sealed class TypeChecker
|
||||
|
||||
private ExpressionNode CheckExpression(ExpressionSyntax node, NubType? expectedType = null)
|
||||
{
|
||||
var result = node switch
|
||||
return node switch
|
||||
{
|
||||
AddressOfSyntax expression => CheckAddressOf(expression),
|
||||
ArrayIndexAccessSyntax expression => CheckArrayIndexAccess(expression),
|
||||
ArrayInitializerSyntax expression => CheckArrayInitializer(expression),
|
||||
AddressOfSyntax expression => CheckAddressOf(expression, expectedType),
|
||||
ArrayIndexAccessSyntax expression => CheckArrayIndexAccess(expression, expectedType),
|
||||
ArrayInitializerSyntax expression => CheckArrayInitializer(expression, expectedType),
|
||||
BinaryExpressionSyntax expression => CheckBinaryExpression(expression, expectedType),
|
||||
UnaryExpressionSyntax expression => CheckUnaryExpression(expression, expectedType),
|
||||
DereferenceSyntax expression => CheckDereference(expression),
|
||||
FuncCallSyntax expression => CheckFuncCall(expression),
|
||||
LocalIdentifierSyntax expression => CheckLocalIdentifier(expression),
|
||||
ModuleIdentifierSyntax expression => CheckModuleIdentifier(expression),
|
||||
BoolLiteralSyntax expression => CheckBoolLiteral(expression),
|
||||
DereferenceSyntax expression => CheckDereference(expression, expectedType),
|
||||
FuncCallSyntax expression => CheckFuncCall(expression, expectedType),
|
||||
LocalIdentifierSyntax expression => CheckLocalIdentifier(expression, expectedType),
|
||||
ModuleIdentifierSyntax expression => CheckModuleIdentifier(expression, expectedType),
|
||||
BoolLiteralSyntax expression => CheckBoolLiteral(expression, expectedType),
|
||||
StringLiteralSyntax expression => CheckStringLiteral(expression, expectedType),
|
||||
IntLiteralSyntax expression => CheckIntLiteral(expression, expectedType),
|
||||
FloatLiteralSyntax expression => CheckFloatLiteral(expression, expectedType),
|
||||
MemberAccessSyntax expression => CheckMemberAccess(expression),
|
||||
MemberAccessSyntax expression => CheckMemberAccess(expression, expectedType),
|
||||
StructInitializerSyntax expression => CheckStructInitializer(expression, expectedType),
|
||||
InterpretBuiltinSyntax expression => CheckExpression(expression.Target) with { Type = ResolveType(expression.Type) },
|
||||
InterpretBuiltinSyntax expression => CheckExpression(expression.Target, expectedType) with { Type = ResolveType(expression.Type) },
|
||||
SizeBuiltinSyntax expression => new SizeBuiltinNode(node.Tokens, new NubIntType(false, 64), ResolveType(expression.Type)),
|
||||
FloatToIntBuiltinSyntax expression => CheckFloatToInt(expression),
|
||||
FloatToIntBuiltinSyntax expression => CheckFloatToInt(expression, expectedType),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(node))
|
||||
};
|
||||
|
||||
if (expectedType == null || result.Type == expectedType)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (result.Type is NubStringType && expectedType is NubCStringType)
|
||||
{
|
||||
return new ConvertStringToCStringNode(node.Tokens, result);
|
||||
}
|
||||
|
||||
if (result.Type is NubCStringType && expectedType is NubStringType)
|
||||
{
|
||||
return new ConvertCStringToStringNode(node.Tokens, result);
|
||||
}
|
||||
|
||||
if (result.Type is NubIntType sourceIntType && expectedType is NubIntType targetIntType)
|
||||
{
|
||||
if (sourceIntType.Signed == targetIntType.Signed && sourceIntType.Width < targetIntType.Width)
|
||||
{
|
||||
return new ConvertIntNode(node.Tokens, targetIntType, result, sourceIntType, targetIntType);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.Type is NubFloatType sourceFloatType && expectedType is NubFloatType targetFloatType)
|
||||
{
|
||||
if (sourceFloatType.Width < targetFloatType.Width)
|
||||
{
|
||||
return new ConvertFloatNode(node.Tokens, targetFloatType, result, sourceFloatType, targetFloatType);
|
||||
}
|
||||
}
|
||||
|
||||
throw new TypeCheckerException(Diagnostic.Error($"Cannot convert {result.Type} to {expectedType}").At(node).Build());
|
||||
}
|
||||
|
||||
private FloatToIntBuiltinNode CheckFloatToInt(FloatToIntBuiltinSyntax expression)
|
||||
// todo(nub31): Infer int type instead of explicit type syntax
|
||||
private FloatToIntBuiltinNode CheckFloatToInt(FloatToIntBuiltinSyntax expression, NubType? _)
|
||||
{
|
||||
var value = CheckExpression(expression.Value);
|
||||
if (value.Type is not NubFloatType sourceFloatType)
|
||||
@@ -316,9 +306,9 @@ public sealed class TypeChecker
|
||||
return new FloatToIntBuiltinNode(expression.Tokens, targetIntType, value, sourceFloatType, targetIntType);
|
||||
}
|
||||
|
||||
private AddressOfNode CheckAddressOf(AddressOfSyntax expression)
|
||||
private AddressOfNode CheckAddressOf(AddressOfSyntax expression, NubType? expectedType)
|
||||
{
|
||||
var target = CheckExpression(expression.Target);
|
||||
var target = CheckExpression(expression.Target, (expectedType as NubPointerType)?.BaseType);
|
||||
if (target is not LValueExpressionNode lvalue)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic.Error("Cannot take address of an rvalue").At(expression).Build());
|
||||
@@ -328,7 +318,7 @@ public sealed class TypeChecker
|
||||
return new AddressOfNode(expression.Tokens, type, lvalue);
|
||||
}
|
||||
|
||||
private ExpressionNode CheckArrayIndexAccess(ArrayIndexAccessSyntax expression)
|
||||
private ExpressionNode CheckArrayIndexAccess(ArrayIndexAccessSyntax expression, NubType? _)
|
||||
{
|
||||
var index = CheckExpression(expression.Index);
|
||||
if (index.Type is not NubIntType)
|
||||
@@ -349,7 +339,8 @@ public sealed class TypeChecker
|
||||
};
|
||||
}
|
||||
|
||||
private ArrayInitializerNode CheckArrayInitializer(ArrayInitializerSyntax expression)
|
||||
// todo(nub31): Allow type inference instead of specifying type in syntax. Something like just []
|
||||
private ArrayInitializerNode CheckArrayInitializer(ArrayInitializerSyntax expression, NubType? _)
|
||||
{
|
||||
var elementType = ResolveType(expression.ElementType);
|
||||
var type = new NubArrayType(elementType);
|
||||
@@ -387,7 +378,6 @@ public sealed class TypeChecker
|
||||
case BinaryOperatorSyntax.Equal:
|
||||
case BinaryOperatorSyntax.NotEqual:
|
||||
{
|
||||
// note(nub31): Expected type should not be passed down since the resulting type is different than operands
|
||||
var left = CheckExpression(expression.Left);
|
||||
if (left.Type is not NubIntType and not NubFloatType and not NubBoolType)
|
||||
{
|
||||
@@ -406,7 +396,6 @@ public sealed class TypeChecker
|
||||
case BinaryOperatorSyntax.LessThan:
|
||||
case BinaryOperatorSyntax.LessThanOrEqual:
|
||||
{
|
||||
// note(nub31): Expected type should not be passed down since the resulting type is different than operands
|
||||
var left = CheckExpression(expression.Left);
|
||||
if (left.Type is not NubIntType and not NubFloatType)
|
||||
{
|
||||
@@ -423,7 +412,6 @@ public sealed class TypeChecker
|
||||
case BinaryOperatorSyntax.LogicalAnd:
|
||||
case BinaryOperatorSyntax.LogicalOr:
|
||||
{
|
||||
// note(nub31): Expected type should not be passed down since the resulting type is different than operands
|
||||
var left = CheckExpression(expression.Left);
|
||||
if (left.Type is not NubBoolType)
|
||||
{
|
||||
@@ -440,16 +428,16 @@ public sealed class TypeChecker
|
||||
case BinaryOperatorSyntax.Plus:
|
||||
{
|
||||
var left = CheckExpression(expression.Left, expectedType);
|
||||
if (left.Type is NubIntType or NubFloatType or NubStringType or NubCStringType)
|
||||
if (left.Type is not NubIntType and not NubFloatType and not NubStringType and not NubCStringType)
|
||||
{
|
||||
var right = CheckExpression(expression.Right, left.Type);
|
||||
return new BinaryExpressionNode(expression.Tokens, left.Type, left, op, right);
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error("The plus operator must be used with int, float, cstring or string types")
|
||||
.At(expression.Left)
|
||||
.Build());
|
||||
}
|
||||
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error("The plus operator must be used with int, float, cstring or string types")
|
||||
.At(expression.Left)
|
||||
.Build());
|
||||
var right = CheckExpression(expression.Right, left.Type);
|
||||
return new BinaryExpressionNode(expression.Tokens, left.Type, left, op, right);
|
||||
}
|
||||
case BinaryOperatorSyntax.Minus:
|
||||
case BinaryOperatorSyntax.Multiply:
|
||||
@@ -532,7 +520,7 @@ public sealed class TypeChecker
|
||||
}
|
||||
}
|
||||
|
||||
private DereferenceNode CheckDereference(DereferenceSyntax expression)
|
||||
private DereferenceNode CheckDereference(DereferenceSyntax expression, NubType? _)
|
||||
{
|
||||
var target = CheckExpression(expression.Target);
|
||||
if (target.Type is not NubPointerType pointerType)
|
||||
@@ -543,7 +531,7 @@ public sealed class TypeChecker
|
||||
return new DereferenceNode(expression.Tokens, pointerType.BaseType, target);
|
||||
}
|
||||
|
||||
private FuncCallNode CheckFuncCall(FuncCallSyntax expression)
|
||||
private FuncCallNode CheckFuncCall(FuncCallSyntax expression, NubType? _)
|
||||
{
|
||||
var accessor = CheckExpression(expression.Expression);
|
||||
if (accessor.Type is not NubFuncType funcType)
|
||||
@@ -563,13 +551,13 @@ public sealed class TypeChecker
|
||||
for (var i = 0; i < expression.Parameters.Count; i++)
|
||||
{
|
||||
var parameter = expression.Parameters[i];
|
||||
var expectedType = funcType.Parameters[i];
|
||||
var expectedParameterType = funcType.Parameters[i];
|
||||
|
||||
var parameterExpression = CheckExpression(parameter, expectedType);
|
||||
if (parameterExpression.Type != expectedType)
|
||||
var parameterExpression = CheckExpression(parameter, expectedParameterType);
|
||||
if (parameterExpression.Type != expectedParameterType)
|
||||
{
|
||||
throw new TypeCheckerException(Diagnostic
|
||||
.Error($"Parameter {i + 1} does not match the type {expectedType} for function {funcType}")
|
||||
.Error($"Parameter {i + 1} does not match the type {expectedParameterType} for function {funcType}")
|
||||
.At(parameter)
|
||||
.Build());
|
||||
}
|
||||
@@ -580,7 +568,7 @@ public sealed class TypeChecker
|
||||
return new FuncCallNode(expression.Tokens, funcType.ReturnType, accessor, parameters);
|
||||
}
|
||||
|
||||
private ExpressionNode CheckLocalIdentifier(LocalIdentifierSyntax expression)
|
||||
private ExpressionNode CheckLocalIdentifier(LocalIdentifierSyntax expression, NubType? _)
|
||||
{
|
||||
var scopeIdent = CurrentScope.LookupVariable(expression.Name);
|
||||
if (scopeIdent != null)
|
||||
@@ -601,7 +589,7 @@ public sealed class TypeChecker
|
||||
throw new TypeCheckerException(Diagnostic.Error($"Symbol {expression.Name} not found").At(expression).Build());
|
||||
}
|
||||
|
||||
private ExpressionNode CheckModuleIdentifier(ModuleIdentifierSyntax expression)
|
||||
private ExpressionNode CheckModuleIdentifier(ModuleIdentifierSyntax expression, NubType? _)
|
||||
{
|
||||
if (!_importedModules.TryGetValue(expression.Module, out var module))
|
||||
{
|
||||
@@ -630,51 +618,62 @@ public sealed class TypeChecker
|
||||
|
||||
private ExpressionNode CheckStringLiteral(StringLiteralSyntax expression, NubType? expectedType)
|
||||
{
|
||||
return expectedType switch
|
||||
if (expectedType is NubCStringType)
|
||||
{
|
||||
NubCStringType => new CStringLiteralNode(expression.Tokens, expectedType, expression.Value),
|
||||
NubStringType => new StringLiteralNode(expression.Tokens, expectedType, expression.Value),
|
||||
_ => new StringLiteralNode(expression.Tokens, new NubStringType(), expression.Value)
|
||||
};
|
||||
return new CStringLiteralNode(expression.Tokens, expression.Value);
|
||||
}
|
||||
|
||||
return new StringLiteralNode(expression.Tokens, expression.Value);
|
||||
}
|
||||
|
||||
private ExpressionNode CheckIntLiteral(IntLiteralSyntax expression, NubType? expectedType)
|
||||
{
|
||||
if (expectedType is NubIntType intType)
|
||||
{
|
||||
return intType.Signed
|
||||
? new IntLiteralNode(expression.Tokens, intType, Convert.ToInt64(expression.Value, expression.Base))
|
||||
: new UIntLiteralNode(expression.Tokens, intType, Convert.ToUInt64(expression.Value, expression.Base));
|
||||
return intType.Width switch
|
||||
{
|
||||
8 => intType.Signed ? new I8LiteralNode(expression.Tokens, Convert.ToSByte(expression.Value, expression.Base)) : new U8LiteralNode(expression.Tokens, Convert.ToByte(expression.Value, expression.Base)),
|
||||
16 => intType.Signed ? new I16LiteralNode(expression.Tokens, Convert.ToInt16(expression.Value, expression.Base)) : new U16LiteralNode(expression.Tokens, Convert.ToUInt16(expression.Value, expression.Base)),
|
||||
32 => intType.Signed ? new I32LiteralNode(expression.Tokens, Convert.ToInt32(expression.Value, expression.Base)) : new U32LiteralNode(expression.Tokens, Convert.ToUInt32(expression.Value, expression.Base)),
|
||||
64 => intType.Signed ? new I64LiteralNode(expression.Tokens, Convert.ToInt64(expression.Value, expression.Base)) : new U64LiteralNode(expression.Tokens, Convert.ToUInt64(expression.Value, expression.Base)),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
|
||||
if (expectedType is NubFloatType floatType)
|
||||
{
|
||||
return floatType.Width switch
|
||||
{
|
||||
32 => new Float32LiteralNode(expression.Tokens, floatType, Convert.ToSingle(Convert.ToInt64(expression.Value, expression.Base))),
|
||||
64 => new Float64LiteralNode(expression.Tokens, floatType, Convert.ToDouble(Convert.ToInt64(expression.Value, expression.Base))),
|
||||
32 => new Float32LiteralNode(expression.Tokens, Convert.ToSingle(expression.Value)),
|
||||
64 => new Float64LiteralNode(expression.Tokens, Convert.ToDouble(expression.Value)),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
|
||||
var type = new NubIntType(true, 64);
|
||||
return new IntLiteralNode(expression.Tokens, type, Convert.ToInt64(expression.Value, expression.Base));
|
||||
return new I64LiteralNode(expression.Tokens, Convert.ToInt64(expression.Value, expression.Base));
|
||||
}
|
||||
|
||||
private ExpressionNode CheckFloatLiteral(FloatLiteralSyntax expression, NubType? expectedType)
|
||||
{
|
||||
var type = expectedType as NubFloatType ?? new NubFloatType(64);
|
||||
return type.Width == 32
|
||||
? new Float32LiteralNode(expression.Tokens, type, Convert.ToSingle(expression.Value))
|
||||
: new Float64LiteralNode(expression.Tokens, type, Convert.ToDouble(expression.Value));
|
||||
if (expectedType is NubFloatType floatType)
|
||||
{
|
||||
return floatType.Width switch
|
||||
{
|
||||
32 => new Float32LiteralNode(expression.Tokens, Convert.ToSingle(expression.Value)),
|
||||
64 => new Float64LiteralNode(expression.Tokens, Convert.ToDouble(expression.Value)),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
}
|
||||
|
||||
return new Float64LiteralNode(expression.Tokens, Convert.ToDouble(expression.Value));
|
||||
}
|
||||
|
||||
private BoolLiteralNode CheckBoolLiteral(BoolLiteralSyntax expression)
|
||||
private BoolLiteralNode CheckBoolLiteral(BoolLiteralSyntax expression, NubType? _)
|
||||
{
|
||||
return new BoolLiteralNode(expression.Tokens, new NubBoolType(), expression.Value);
|
||||
}
|
||||
|
||||
private ExpressionNode CheckMemberAccess(MemberAccessSyntax expression)
|
||||
private ExpressionNode CheckMemberAccess(MemberAccessSyntax expression, NubType? _)
|
||||
{
|
||||
var target = CheckExpression(expression.Target);
|
||||
switch (target.Type)
|
||||
@@ -897,6 +896,7 @@ public record Variable(string Name, NubType Type);
|
||||
|
||||
public class Scope(string module, Scope? parent = null)
|
||||
{
|
||||
private NubType? _returnType;
|
||||
private readonly List<Variable> _variables = [];
|
||||
public string Module { get; } = module;
|
||||
|
||||
@@ -905,6 +905,16 @@ public class Scope(string module, Scope? parent = null)
|
||||
_variables.Add(variable);
|
||||
}
|
||||
|
||||
public void SetReturnType(NubType returnType)
|
||||
{
|
||||
_returnType = returnType;
|
||||
}
|
||||
|
||||
public NubType? GetReturnType()
|
||||
{
|
||||
return _returnType ?? parent?.GetReturnType();
|
||||
}
|
||||
|
||||
public Variable? LookupVariable(string name)
|
||||
{
|
||||
var variable = _variables.FirstOrDefault(x => x.Name == name);
|
||||
|
||||
Reference in New Issue
Block a user